在 2.0 版本中,您可以使用下列代码在某个套接字上启动异步发送操作:
void OnSendCompletion(IAsyncResult ar) { }
IAsyncResult ar = socket.BeginSend(buffer, 0, buffer.Length,
SocketFlags.None, OnSendCompletion, state);
在新版本中,您还可以实现:
void OnSendCompletion(object src, SocketAsyncEventArgs sae) { }
SocketAsyncEventArgs sae = new SocketAsyncEventArgs();
sae.Completed += OnSendCompletion;
sae.SetBuffer(buffer, 0, buffer.Length);
socket.SendAsync(sae);
这 里有一些明显的差别。封装操作上下文的是一个SocketAsyncEventArgs对象,而不是IAsyncResult对象。该应用程序创建并管理 (甚至可以重复使用)SocketAsyncEventArgs对象。套接字操作的所有参数都由SocketAsyncEventArgs对象的属性和方 法指定。完成状态也由SocketAsyncEventArgs对象的属性提供。最后,需要使用事件处理程序回调完成方法。
上述是MSDN的一些中文翻译,SocketAsyncEventArgs的介绍确实太少,具体的应用成体系的更少,但是SocketAsyncEventArgs又是.net中进行高性能服务器端编程所必需的。
通过这几天查阅SocketAsyncEventArgs的相关资料,以及对SocketAsyncEventArgs的初步使用尝试,发现这种基于IO完成端口的事件通知机制,在通知缓存层确实能提高很大的效率,增加了端口的复用,并且减少了托管堆上对象的分配和线程数量,基于SocketAsyncEventArgs的编程模型,是区别于以往的模型,以我的理解,其利用IO完成端口在端口上复用之后,利用完成事件进行通知,通知的仅仅是一个信号量,具体的调用之前,还需要预先声明很大的全局缓存存储区,所有的缓存层数据都被置放到全局存储区上,这确实减少了新对象的生成和过多的上下文切换。到了具体的数据处理时,本质上还是需要切换到线程池中,也少不了资源的调用。
SocketAsyncEventArgs的完成事件是属于在一个独立的线程栈上,虽然实现了快速的IO事件的应答,但是在超过一定核数的处理器上和足够大的内存上,这种处理机制未必有APM的执行效率高,但是如果在服务器资源紧缺的场合,这种机制应该效率会很高。
由于在UDP服务器端处理时,按照TCP处理机制处理不下去了,才查阅到SocketAsyncEventArgs这种处理机制,国内开源框架SuperSocket中的核心部分也是采用这种机制。
以上纯属个人理解,可能理解有误,正在查阅有关的技术文档,如果理解有误,会在以后更正注解。