姜 立
(辽宁轨道交通职业学院,辽宁 沈阳 110023)
在日常生活中,对于一个中等规模的应用来说,同时达到千人以上在线的情况经常发生,系统集群可以很好地解决这个问题。现实情况下,一些应用不可能投入大量硬件设备,因为硬件设备价格高昂。如何能利用有限的系统资源,解决比较困难的部署问题,成为计算机软件行业研究的主要问题。在设计过程中,如果采用一个用户一个线程的设计方式那将造成CPU在成千上万的线程间进行切换,后果不可想象,用户多一点的时候完全解决不了问题,甚至系统崩溃。而Windows系统为我们提供了一个强大的工具,那就是完成端口(IOCP)[1]。
重叠I/O(Overlapped I/O),完成端口(Completion Ports),Windows完成端口把完成端口看成需要系统维护的队列,应用调用系统接口,把重叠IO操作完成的事件放入队列,用不同的CPU内核处理的强大功能。
(1)很多现网应用服务器采用的是Windows server系统,Windows server系统有诸多优点。而Windows IOCP就是Windows系统独有的、系统自带的强大功能,而其他系统要实现重叠IO功能,都需要应用自身实现,大大增加了开发难度。
(2)Windows IOCP完成端口技术则完全颠覆传统设计模式,将并行的线程数量设计上限。目前IOCP完成端口是Windows下性能最好的I/O模型,同时它也是最复杂的内核对象[2]。其避免了大量用户并发时原有模型采用的方式,极大地提高了程序的并行处理能力。完成端口会充分利用Windows内核来进行I/O的调度,是C/S通信模式中性能最好的网络通信模型。使用“同步”的方式操作会阻塞住来自同一个线程的任何其他操作,所以要设计出高性能的服务器程序,通信一定要是异步的。完成端口模型的初衷,是为了解决一个客户端一个连接线程的巨大缺点,充分利用内核对象的调度,只使用少量的几个线程来处理和客户端的所有通信,消除了无谓的线程上下切换,最大限度地提高了网络通信的性能。
(3)提供长连接、短连接,RPC级功能实现。
所谓异步,区别于同步的地方就是同步可以理解为多个工作大家排对按顺序一个接一个完成,所需要的时间是每个任务时间之和,异步操作则是大家同时开始工作,所需要的时间就是子任务里边时间最长的。这样就可以简单通俗地理解异步操作的性能优势,Windows的IOCP就是异步操作的最完美实例。
Windows的IOCP负责任务的调度和完成通知。设备句柄为同步对象,有两种信号状态:有或无。无信号状态:IO请求发送时处理时;有信号状态:操作完成时。可见,只有在任务完成时设备句柄信号才有有信号状态。此时系统受信,系统通过Wait For Multiple Objects(或Wait For Single object)接口判断操作是否完成[3]。
系统事件和IO操作一一对应,进行绑定。系统通过事件处理API处理IO操作,由于事件API本身就是异步高效操作,和IO操作结合,很好地简化了操作流程。当I/O操作完成后系统采用事件API通知绑定的IO句柄,事件授信,IO执行操作完成。该技术解决了使一个设备内核对象变为有信号技术中一个设备只能对应一个操作的不足。
(1)大型多人在线游戏类型游戏(MMO游戏),目前大型的MMO游戏都采用了IOCP完成端口,如《三国鼎立》《英雄远征》等。
(2)大型IM(即时通讯、实时传讯)系统,IOCP提供长连接、短连接,可以简单实现心跳机制,确保设备在线,应对运营商连接清理机制。
(3)企业ERP管理系统等等具有大量并发用户请求的场合。
(4)稳定、高效的IOCP完成端口通信模型几乎成为开发这类系统的基础。
系统采用C/S结构设计,主要分为登录、用户管理、信息管理、设备管理管理、设备控制等模块。服务器端应用完成端口技术,客户端采用普通的Socket连接方式。服务器端数据库系统采用MySql。系统通过IOCP服务器来访问数据库系统,用户通过客户端软件进行Socket短连接到IOCP服务器,进行数据操作[4]。
(1)创建完成端口。
HANDLE m_hIOCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
(2)根据系统中CPU核心的数量建立对应的Worker线程。
SYSTEM_INFO si;
GetSystemInfo(&si) ;
int m_nProcessors = si.dwNumberOfProcessors;
m_phWorkerThreads[i] = ::CreateThread(0, 0, _WorkerThread, …) ;
(3)创建用于监听的Socket,绑定到完成端口上,然后开始在指定的端口上监听连接请求。
SOCKET m_sockListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
If(SOCKET_ERROR==bind(m_sockListen,(struct sockaddr*)&ServerAddress, sizeof(ServerAddress)));
listen(m_sockListen,SOMAXCONN)) ;
(4)在这个监听Socket上投递AcceptEx请求。
GUID GuidAcceptEx = WSAID_ACCEPTEX; WSAIoctl(m_pListenContext->m_Socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx,sizeof(GuidAcceptEx), &m_lpfnAcceptEx, sizeof(m_lpfnAcceptEx) , &dwBytes, NULL,NULL) ;
(5)Worker线程的工作。
BOOL bReturn=GetQueuedCompletionStatus(pIOCPModel->m_hIOCompletionPort,
(LPDWORD)&lpContext,&pOverlapped,INFINITE );
(6)收到Accept通知时执行_DoAccept。
(7)当收到Recv通知时, _DoRecv。
目前高性能异步IO技术已经日趋成熟,各大顶尖技术公司和知名企业都有自己的实现机制和方法。当前主流技术已经在高性能异步IO技术上继续演进为微服务和云等,如阿里的Dubbo和apache的Spring Cloud等。但是Winows完成端口技术依然在特定环境为我们提供了一个可行的免费的解决方案,而且实现代价低,一台普通的PC电脑便可以发挥出类似服务器的功能,可以承接大部分小型应用,因此目前仍然有很多技术人员热衷于Winows完成端口技术的研究和开发。