您的位置:首页 > 理论基础 > 计算机网络

C#异步SOCKET发送帮肋类,支持UDP,TCP

2015-08-29 11:59 543 查看
由于采用了池技术,需要指定最大池容量,以保证内存不泄漏.

另外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; }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: