关于SocketAsyncEventArgs的一些理解

作为IOCP关键类SocketAsyncEventArgs的补充知识,摘抄2007年9月MSDN杂志上的“连接.NET框架3.5 ”的部分内容如下: .NET Framework中的APM也称为Begin/End模式。这是因为会调用Begin方法来启动异步操作,然后返回一个IAsyncResult 对象。可以选择将一个代理作为参数提供给Begin方法,异步操作完成时会调用该方法。或者,一个线程可以等待 IAsyncResult.AsyncWaitHandle。当回调被调用或发出等待信号时,就会调用End方法来获取异步操作的结果。这种模式很灵活, 使用相对简单,在 .NET Framework 中非常常见。 但是,您必须注意,如果进行大量异步套接字操作,是要付出代价的。针对每次操作,都必须创建一个IAsyncResult对象,而且该对 象不能被重复使用。由于大量使用对象分配和垃圾收集,这会影响性能。为了解决这个问题,新版本提供了另一个使用套接字上执行异步I/O的方法模式。这种新 模式并不要求为每个套接字操作分配操作上下文对象。 我们没有创建全新的模式,而只是采用现有模式并做了一个基本更改。现在,在Socket类中有了一些方法,它们使用基于事件的完成模型的变体

在 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中的核心部分也是采用这种机制。

以上纯属个人理解,可能理解有误,正在查阅有关的技术文档,如果理解有误,会在以后更正注解。

你可能感兴趣的:(关于SocketAsyncEventArgs的一些理解)