这两天粗略的学习了完成端口的简单应用今天把他记下来!
IOCP(I/O CompletionPort) I/O完成端口;
IOCP模型属于一种通讯模型,适用于(能控制并发执行的)高负载服务器的一个技术。一种能够处理很多很多用户的数据交换的一个模型,主要还是异步I/O操作的模型,不过由于是内核操作,很多东西都是windows设计好的,最起码线程安全由系统负责。
主要的优点有:利于管理,分配线程,控制并发,最小化的线程上下文切换。优化线程调度,提高CPU和内存缓冲的命中率。可以帮助维护重复使用的内存池。去除删除线程创建/终结负担。
相对而言:IOCP是一种大规模连接,小数据传送。如果带宽够大,传数据只需几十个或者小于60个,就能搞定,那还不如用I/O事件选择。更快捷、还能保证安全。我们这里应用IOCP应用的是串型传输,可能影响速率,但是保证安全,完整传输。
首先说一下主要用到的API函数,当然主要是关于完成端口的:
最主要的一个函数CreateIoCompletionPort
HANDLE WINAPI CreateIoCompletionPort(
__in HANDLE FileHandle, //关联文件句柄
__in_opt HANDLE ExistingCompletionPort, //已存在的文件句柄
__in ULONG_PTR CompletionKey, //传送给处理函数的参数 ,是个结构体里面有Client的信息(SOCKET和地址)
__in DWORD NumberOfConcurrentThreads //有多少个线程在访问这个消息队列
);
下一就是“完成”后的消息的队列,内核完成的操作都在里面,这是I/O操作,用的是异步通信,也就是内核处理数据,线程继续运行,最后完成该线程工作。
BOOL WINAPI GetQueuedCompletionStatus( __in HANDLE CompletionPort, // 已建立的文件句柄
__out LPDWORD lpNumberOfBytes, //完成一次I/O操作后,接收实际传输的字节数 __out PULONG_PTR lpCompletionKey, //完成端口里面的信息地址 __out LPOVERLAPPED* lpOverlapped, //重叠结构内的信息地址 __in DWORD dwMilliseconds //处理时间 );
剩下最后一个就是如何正确关闭I/O完成端口
BOOL WINAPI PostQueuedCompletionStatus( __in HANDLE CompletionPort, __in DWORD dwNumberOfBytesTransferred, __in ULONG_PTR dwCompletionKey, __in LPOVERLAPPED lpOverlapped );
基本样例就是
PostQueuedCompletionStatus(m_hIOCompletionPort, 0, (DWORD) NULL, NULL);
下面就是具体过程:
一、首先要建立一个完成端口:里面的参数可能都是0和-1,并且确定要创建的线程数(和自己的CPU有直接关系)
二、判断系统内到底多少个处理器
三、根据处理器数量创建线程
四、套接字操作,直接运行到监听完成。
五、使用accept函数,接受入站的连接请求。
六、创建数据结构主要用于容纳单句柄数据,我这里主要涉及到的有SOCKET和ClientAddr。还有重叠数据结构里面涉及到的有LPOVERLAPPED,缓存,类型
七、把ClientSkt和完成端口关联到一起。并且把单句柄数据结构传递进CreateIoCompletionPort();
八、使用重叠I/O,在套接字上投递一个或多个WSASend和WSARecv调用。
九、线程开始运行。如果线程结束,回收堆内存。由于使用的是全局堆栈内存,所以可以在其他地方回收内存。当GetQueueCompletionStatus值为0时,阻塞中,这种情况说的是前面没有运行过,如果在运行中出现为零就需要考虑回收资源。当然还有一种情况就是操作完成时,也要回收资源。
十、关闭I/O完成端口。
这些都是看书,直接总结的,有不足的地方,互相探讨