参考原帖地址:https://blog.csdn.net/beyond_cn/article/details/9336043
一、概念
1. 完成端口IOCP是一个异步IO模型, IO设计模式 属于Proactor。
2. 它开启多个工作者线程,每个工作者线程负责多个socket的处理。
3. 它利用操作系统的内核程序来并发处理多个IO,避免某个线程被单个耗时的IO操作卡死,有效地提升CPU效率。
4. 它还帮应用程序从IO读取数据至内存缓冲区,不需要应用程序亲自处理。
二、优点
1. 充分利用操作系统内核来进行I/O的调度,是用于C/S通信模式中性能最好的网络通信模型。
2. 使用少量的几个线程来处理大量客户端的所有通信,消除了无谓的线程上下文切换。
三、如何实现多线程的负载均衡
1. IOCP事先开好几个线程,CPU数 * 2 + 2。
2. 等到有用户请求来到的时候,就把这些请求都加入到一个公共队列中去。
3. 这几个开好的线程就排队逐一去从消息队列中取出消息并加以处理。
这种方式就很优雅地实现了异步通信和负载均衡的问题
四、为什么叫 重叠结构"Overlapped"
执行I/O请求的时间与线程执行其他任务的时间是重叠(overlapped)的
Windows里所有的异步通信都是基于这个 重叠结构 完成端口也不例外。
五、为什么叫 完成端口"CompletionPort"
系统会在网络I/O操作“完成”之后才会通知应用程序。
来自于网络上的数据已经接收完毕了;或者是客户端的连入请求已经被系统接入完毕了等等。
六、使用完成端口的基本流程
1. 调用 CreateIoCompletionPort() 函数创建一个完成端口,只需要建立一个,保存好句柄。
2. 建立多少个工作者,专门用来和客户端进行通信。
3. 接收连入的Socket连接,两种实现方式:
(1) 启动一个独立的线程,专门用来accept客户端的连接请求
(2) 性能更高更好的异步AcceptEx()请求,但代码比较复杂。
4. 有客户端连入的时候,调用CreateIoCompletionPort(),把新连入的Socket,与前面创建的完成端口绑定在一起。
5. 客户端连入之后,在这个Socket上提交一个网络请求,例如WSARecv(),系统就会执行接收数据的操作。
6. 工作者线程调用GetQueuedCompletionStatus() ,扫描完成端口的队列里是否有网络通信的请求存在。 有的话,就将这个请求从队列中取回来,继续执行后面的代码,如此循环。
七、AcceptEx的特点
1. AcceptEx取消了专门用于accept连接的线程。在工作者线程中,根据GetQueuedCompletionStatus() 的返回的操作类型,判断是不是Accept操作。 如果是,就执行_doAccept()
2. AcceptEx相比Accept的好处:
(1) 在客户端连入之前,就把客户端的Socket建立好了
(2) AcceptEx可以同时投递多个请求 (普通的Accept是单个阻塞)
(3) 投递AcceptEx的时候,还可以顺便收取客户端发来的第一组数据 (客户端的连接信息)
3. 缺点:AcceptEx使用起来要麻烦得多