异步SOCKET心得
异步SOCKET心得
将最近在网络通讯项目中对Socket使用的一些经验总结如下。
1. 不要在异步完成方法中进行耗时的调用。
这里的异步完成方法在.NET FRAMEWORK 2.0对应于异步操作的回调方法,以Socket.BeginSend方法为例如下。
public IAsyncResult BeginSend(
byte[] buffer,
int offset,
int size,
SocketFlags socketFlags,
out SocketError errorCode,
AsyncCallback callback,
Object state
)
参数“callback”是一个委托,代表在发送完毕后,在IOCP线程中将要调用的回调方法。
.NET FRAMEWORK 2.0 SP1和SP2中添加了一个类SocketAsyncEventArgs,它的事件Completed同样是在IOCP线程中触发的,用于在IOCP线程中处理异步操作的完成。
后文所说的异步完成方法就对应“callback委托和Completed事件。
下面说为什么不能在异步完成方法中进行耗时的操作。
IOCP线程开启的个数和CPU核数有关(经过试验),默认情况下开启的IOCP线程数据和CPU数目一致。即时调用了ThreadPool.SetMaxThreads和ThreadPool.SetMaxThreads方法 ,单核CPU上只默认开启一个IOCP线程,双核则开启两个。当然开启的IOCP线程数也可能超过CPU个数。这发生在已开启的IOCP线程处于阻塞状态(不会分配CPU时间),只有当所有已开启的IOCP线程处于阻塞状态时才会有开启新的IOCP线程。
可以确定在任意时刻可执行(为处于休眠状态)的IOCP线程的数目都不会超过CPU核数。所有异步操作完成后都在IOCP队列排队,等待取出后调用异步完成方法。
2. 异步建立连接。
当远程端口未建立监听时,同步建立连接(Connect)将会很耗时、尤其是当远程主机并未开启时。
3. 同步接受(Accept)连入的套接字。
异步接受(AcceptAsync、BeginAccept)连入的套接字,接受完成后要在IOCP队列排队,前面说过所有的异步操作完成后都要在IOCP队列排队,可能接受完成前面已经有很多需要处理的完成操作,可能会很耗很多时间。这样就造成了监听队列中套接字不断增加,达到最大值后,便无法连入新的套接字。造成远程主机连接失败。在一个循环中同步接受连入的套接字,可以尽快的从监听队列中取出连入的套接字,加快对连接的响应。