本文章介绍C#中的IOCP(输入输出完成端口)模型,探讨其简洁性、实用性及高效率特点,适合网络编程需求。
最近我参与了一个项目,需要开发一个高性能的网络服务器,并在网络上搜索到了一些C++版本的相关资料以及简单的DEMO。由于这些资源都是英文且不够全面,所以我决定使用C#编写了这个DEMO来处理接收到的数据。
1. 在C#中,我们不需要直接操作完成端口的操作系统内核对象;Microsoft已经为我们提供了SocketAsyncEventArgs类,它封装了IOCP的使用。
2. 我设计了一个名为SocketAsyncEventArgsPool的类,利用List对象存储用于客户端通信的SocketAsyncEventArgs对象。这种方式比用堆栈实现更便于管理:在池中可以轻松找到并主动向任何连接到服务器的客户发送信息;而若采用堆栈方式,则需要额外的设计来跟踪已连接上的客户端。
3. 对于每个客户端,无论是发送还是接收数据时都使用同一个SocketAsyncEventArgs对象。这意味着对于每一个特定的客户端来说,通信是同步进行的:要么正在投递一个发送请求并等待响应,或者在准备接受数据和等待中。
4. SocketAsyncEventArgs类中的UserToken属性直接设置为被接收到的客户端socket。
5. 本DEMO没有使用BufferManager 类。初始化时给每个SocketAsyncEventArgsPool对象分配缓冲区,并通过Array.Copy方法进行字符拷贝;发送时不改变缓冲区的位置,只调整使用的长度,在下次接收请求前恢复原有长度即可。如果需要主动向客户发信息,则可以创建新的SocketAsyncEventArgs对象或在初始化中预留一些用于专门的信息群发。
6. 测试结果:在我的笔记本上(配置为T420 I7 8G内存)进行了测试,100个客户端持续发送和接收数据共进行了一千万次操作。在整个过程中没有间隔的睡眠时间,并且整个过程耗时3004.6325秒完成;平均每分钟可以处理大约199,691.6 次请求;平均一秒内能处理约 3,328.2 次发送与接收操作。在测试过程中,内存使用量从开始后两分钟左右就保持稳定不再增加,并且对每个客户端的延迟最高不超过2秒。