最初.NET并没有提供SocketAsyncEventArgs对象给Socket进行使用,只是提供同步和异步(Begin/End)模式。但在.net 1.0发布后才发现异步(Begin/End)模式并不适合高并发吞吐的需求,主要因为这种模式下会产生大量的异步回调对象从而影响GC的性能。在.Net 1.1升级为了提升这一块的性能,引用了SocketAsyncEventArgs对象;这个对象可以用在accept,send和receive等操作中,由于有着可复用性所以在高吞吐下有着更出色的性能表现。
虽然十几年过去了,但还有不少普通开发者喜欢用同步或异步(Begin/End)模式,实际上为了得到更好的性能建议统一使用SocketAsyncEventArgs来进行Socket的相关操作。使用这个对象需要关注以下几个属性,方法和事件。
BufferList
设置接收和发送的缓存冲,这个属性是一个IList
BytesTransferred
获取当前接收或发送完成的字节数量,当接收为0零的情况下表示连接已经关闭无须再次调用接收;在发送完成后判断完成数量是否和设置发送缓冲区数量设置是否一致,如果小于缓冲区的数量即需要做下偏移发送剩下的内容(.net core暂无发现这情况,但在代码处理上建议做这判断)。
ConnectSocket
些属于用于获取当前Accept的Socket,这属性只有在AcceptAsync时有用(注意:在调用Socket.AcceptAsync前请把该属性进行一个清空).
SocketError
获取Socket相关操作状态,虽然是名称上是错误,但成功状态也是它的状态之一。此状态值非常有用,通过不同的值可以得到连接不可用状态是由什么引起的,对于网络上的错误排查非常有用。以下是连接是不同状态的详细描述。
https://docs.microsoft.com/zh-cn/dotnet/api/system.net.sockets.socketerror?view=netcore-3.1
SetBuffer
设置接收或发送的缓冲区和BufferList属性有所不同,此方法只能设置一个缓冲区。
Completed
异步操作完成事件,这个事件是在Socket相关操作后异步回调事件;这个事件的回调对象包括完成的情况状态。往往在这个事件中完成工作要重新如:AcceptAsync和ReceiveAsyn。注意:当相关操作是同步完成的情况下是不会触发事件,这个时候需要手动调用相关事件引用的方法。
UserToken
用户自定义信息,在操作前把需要传递的信息设置到该属性上,然后在完成事件进行获取处理。一般用于保存当前Socket对应的会话状态信息。
扩展功能
SocketAsyncEventArgs对象是可以继承的,OnCompleted方法也可以重写;可以根据自己的需要继承它来扩展一些更方便的功能来满足需求。组件为了后期方便使用也是从SocketAsyncEventArgs派生出一个新的对象SocketAsyncEventArgsX
public class SocketAsyncEventArgsX : SocketAsyncEventArgs{protected override void OnCompleted(SocketAsyncEventArgs e){base.OnCompleted(e);if (e.SocketError != SocketError.Success){LastSocket = null;}}public IBuffer BufferX{get;internal set;}public bool IsReceive{get;set;}public ISession Session { get; internal set; }public void AsyncFrom(System.Net.Sockets.Socket socket, object useToken, int size)public void AsyncFrom(ISession session, object useToken, int size)public void AsyncTo(System.Net.Sockets.Socket socket, object userToken, int length)public void AsyncTo(ISession session, object userToken, int length)}
在这里扩展比较简单主要是为了操作更方便,加了一些发送和接收的方法,对应的会话对象和关联缓存对象。这样封装后SocketAsyncEventArgs除了针对Socket操作外还能直接针对会话对象进行操作。

