由于采用了池技术,需要指定最大池容量,以保证内存不泄漏.
另外C#中大量创造 SocketAsyncEventArgs会导致内存不能回收,
using System; using System.Collections.Concurrent; using System.Net; using System.Net.Sockets; using System.Text; using System.Collections.Generic; using System.Linq; /// <summary> /// 用于辅助异步发送Socket的帮肋类 /// Ver1.2 增加了对 AsyncSendResult 的池管理,原因为发送数据时,占用了过大的内存. /// 增加了对不受控制的对像记数功能. /// </summary> public class AsyncSocketSendHelper { #region 客户端联接池 /// <summary> /// 接收SAEA池集合 /// </summary> private ConcurrentStack<SocketAsyncEventArgs> ReceiveSocketArgsPool = new ConcurrentStack<SocketAsyncEventArgs>(); /// <summary> /// 初始化接收socketargs对象池 /// </summary> protected void InitReceiveSocketArgsPool() { } /// <summary> /// 创建一个接收SAEA对象,设置最大接收字节数 /// </summary> /// <returns></returns> protected virtual SocketAsyncEventArgs CreateReceiveSocketArgs() { SocketAsyncEventArgs e = new SocketAsyncEventArgs(); e.Completed += IO_SendComleted; return e; } /// <summary> /// 租赁一个接收SAEA对象 /// </summary> /// <returns></returns> protected virtual SocketAsyncEventArgs RentReveiveSocketArgs() { SocketAsyncEventArgs e; //增加已经发出的对像数据 System.Threading.Interlocked.Increment(ref ss); return ReceiveSocketArgsPool.TryPop(out e) ? e : CreateReceiveSocketArgs(); } private ushort _SocketArgsPoolNumber = 200; /// <summary> /// SocketAsyncEventArgs 池最大长度限制 /// </summary> public ushort SocketArgsPoolNumber { get { return _SocketArgsPoolNumber; } set { _SocketArgsPoolNumber = value; } } //设置缓冲区 private byte[] arr = new byte[1]; private long ss; /// <summary> /// 已经创建但是还没有回收的对像个数,如果这个数据超过1000则表示可能有内存泄漏的风险.异步模式下出现 /// </summary> public long OutControlSocketArgsNumber { get { return ss; } } /// <summary> /// 归还一个接收SAEA参数 /// </summary> /// <param name="e">还池</param> protected virtual void GivebackReceiveSocketArgs(SocketAsyncEventArgs e) { if (e != null) { //减少已经发出的对像数据 System.Threading.Interlocked.Decrement(ref ss); e.UserToken = null; //最多只保存200个缓冲接收器功能 if (ReceiveSocketArgsPool.Count > _SocketArgsPoolNumber) { //移除事件 e.Completed -= IO_SendComleted; e.SetBuffer(arr, 0, arr.Length); e.Dispose(); return; } ReceiveSocketArgsPool.Push(e); } } #endregion /// <summary> ///UDP 发送数据服务 /// </summary> /// <param name="socket">用于发送的Socket对像</param> /// <param name="udpTarget">udp远程终端点目标</param> /// <param name="buff">需要发送的数据</param> /// <param name="callBack">回调函数参数为:发送结果,目标节点,发送数据</param> /// <param name="userToken">用户数据 </param> public virtual void SendToAsyncByUDP(Socket socket, byte[] buff, EndPoint udpTarget = null, Action<AsyncSendResult> callBack = null, object userToken = null) { if (socket == null) { throw new NullReferenceException(); } if (buff == null) { throw new NullReferenceException(); } if (udpTarget == null) { throw new NullReferenceException(); } SocketAsyncEventArgs e = RentReveiveSocketArgs(); e.RemoteEndPoint = udpTarget; //设置发送缓冲区 e.SetBuffer(buff, 0, buff.Length); try { //用户标识 var token = new AsyncSendResult { Result = false, RemoteEndPoint = udpTarget.ToString(), SendTime = DateTime.Now, SendData = buff, ResultTime = DateTime.Now, CallBakc = callBack, UserToKen = userToken, }; e.UserToken = token; //发送数据 if (!socket.SendToAsync(e)) { IO_SendComleted(socket, e); } } catch (SocketException) { //还池 GivebackReceiveSocketArgs(e); } catch (ObjectDisposedException) { //还池 GivebackReceiveSocketArgs(e); } } /// <summary> /// 发送数据服务 /// </summary> /// <param name="socket">用于发送的Socket对像</param> /// <param name="buff">需要发送的数据</param> /// <param name="callBack">回调函数参数为:发送结果,目标节点,发送数据</param> /// <param name="userToken">用户数据 </param> /// <returns></returns> public virtual void SendToAsync(Socket socket, byte[] buff, Action<AsyncSendResult> callBack = null, object userToken = null) { if (socket == null) { throw new NullReferenceException(); } if (buff == null) { throw new NullReferenceException(); } SocketAsyncEventArgs e = RentReveiveSocketArgs(); //设置发送缓冲区 e.SetBuffer(buff, 0, buff.Length); try { //用户标识 var token = new AsyncSendResult { Result = false, RemoteEndPoint = socket.RemoteEndPoint.ToString(), SendTime = DateTime.Now, SendData = buff, ResultTime = DateTime.Now, CallBakc = callBack, UserToKen = userToken, }; e.UserToken = token; //发送数据 if (!socket.SendAsync(e)) { IO_SendComleted(socket, e); } } catch (SocketException) { //还池 GivebackReceiveSocketArgs(e); } catch (ObjectDisposedException) { //还池 GivebackReceiveSocketArgs(e); } } /// <summary> /// 发送数据后的完成功能 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected virtual void IO_SendComleted(object sender, SocketAsyncEventArgs e) { try { if (e.UserToken != null) { AsyncSendResult token = e.UserToken as AsyncSendResult; if (token != null) { //设置结果时间 token.ResultTime = DateTime.Now; //发送数据OK if (e.SocketError == SocketError.Success) { token.Result = true; if (token.CallBakc != null) { token.CallBakc(token); } } else { //发送数据失败 token.Result = false; if (token.CallBakc != null) { token.CallBakc(token); } } } } } finally { //还池 GivebackReceiveSocketArgs(e); } } } /// <summary> /// 异步发送结果 /// </summary> public class AsyncSendResult { /// <summary> /// 结果 /// </summary> public bool Result { get; set; } /// <summary> /// 目标节点 /// </summary> public string RemoteEndPoint { get; set; } /// <summary> /// 发送数据 /// </summary> public byte[] SendData { get; set; } /// <summary> /// 发送时间 /// </summary> public DateTime SendTime { get; set; } /// <summary> /// 结果返回时间 /// </summary> public DateTime ResultTime { get; set; } /// <summary> /// 获取或设置与此操作关联的用户或应用程序对象。 /// </summary> public object UserToKen { get; set; } /// <summary> /// 用于回调的委托 /// </summary> internal Action<AsyncSendResult> CallBakc { get; set; } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-30 01:06:30