1.完成端口模型
一、基本概念
完成端口是一种内核对象,它可以与多个文件描述符(如套接字、文件句柄等)相关联,并且允许多个线程同时处理这些文件描述符上的 I/O 操作。
其核心思想是将 I/O 操作的完成通知与线程的分配和管理进行有效的分离,以实现高效的并发处理。
“I/O 操作的完成通知” 的意思是当 I/O 操作(如读取文件、接收网络数据等)完成之后,系统会发出一个通知信息。这种机制可以避免应用程序不断地轮询 I/O 状态以确定操作是否完成,从而提高了系统的效率和响应性能。

二、工作原理
主线程做监听线程
服务线程作为操作线程

- 创建完成端口
- 应用程序首先创建一个完成端口对象。这个对象用于管理和分配系统资源,以及协调多个线程处理 I/O 操作。
- 关联文件描述符和完成端口
- 将需要进行 I/O 操作的文件描述符(如套接字)与完成端口进行关联。这样,当在这些文件描述符(套接字)上发生 I/O 操作完成事件时,系统会将通知发送到对应的完成端口。
- 创建工作线程
- 应用程序创建一组工作线程,这些线程会在完成端口上等待 I/O 操作的完成通知。通常,工作线程的数量可以根据系统的硬件资源(如处理器核心数量)进行调整,以达到最佳的性能。
- I/O 操作与完成通知
- 当应用程序发起一个异步 I/O 操作(如读取数据从网络套接字),系统会在后台执行这个操作。一旦操作完成,系统会将一个完成通知放入完成端口。
- 工作线程处理完成通知
- 工作线程会在完成端口上阻塞等待,当有完成通知到达时,线程会被唤醒并处理这个通知。通知中包含了关于完成的 I/O 操作的信息,如操作的类型、数据长度等。工作线程可以根据这些信息进行进一步的处理,如将读取的数据进行处理或者发送响应数据。
三、优势
- 高效的并发处理
- 完成端口能够有效地管理大量的并发 I/O 操作,通过合理地分配工作线程,可以充分利用系统资源,提高应用程序的性能和响应速度。
- 减少线程上下文切换
- 由于工作线程是在完成端口上等待 I/O 操作的完成通知,而不是频繁地进行轮询或者阻塞在单个 I/O 操作上,因此可以减少线程的上下文切换次数,降低系统开销。
- 可扩展性
- 完成端口模型可以很容易地扩展到处理大量的并发连接,只需要根据系统资源增加工作线程的数量即可。
四、应用场景
- 高性能服务器应用
- 对于需要处理大量并发连接的服务器应用,如网络服务器、数据库服务器等,完成端口 I/O 模型可以提供高效的 I/O 处理能力,保证服务器的性能和响应速度。
- 大规模文件传输
- 在进行大规模文件传输时,完成端口可以有效地管理多个文件的 I/O 操作,提高文件传输的效率。
- 异步数据库访问
- 对于需要进行异步数据库访问的应用程序,完成端口可以与数据库连接进行结合,实现高效的数据库查询和更新操作。
2.代码和勘误:
注意:
本代码来自于《windows网络与通信程序设计》第四章
其中在VS2022中进行编译运行的过程中有一定的错误,曾困扰许久
问题:
在发送完一条消息之后,在服务线程中再次投递的过程中,出现内存访问异常

参数类型的的错误
VS2022会检测到下面代码中的 (DWORD)&pPerHandle出现错误
1 | BOOL bOK = ::GetQueuedCompletionStatus(hCompletion, |
但是无法检测到下面代码中的 (DWORD)pPerHandle出现错误,于是出现参数的不一致,导致出现上述问题
1 | //将新接收的客户端连接绑定到完成端口对象hCompletion上 |
解决办法:
将上述的两条依次代码修改为
1 | BOOL bOK = ::GetQueuedCompletionStatus(hCompletion, |
1 | //将新接收的客户端连接绑定到完成端口对象hCompletion上 |
完整代码如下:
Init.h文件:
1 |
|
Server.cpp
1 |
|
3.函数
1.CreateIoCompletionPort函数
CreateIoCompletionPort 函数有两个功能:
(1)创建一个完成端口对象
(2)把一个IO句柄(套接字)和完成端口关联起来
1 | HANDLE CreateIoCompletionPort ( |

2.GetQueuedCompletionStatus函数
作用就是取得完成端口的结果
这个函数会阻塞直到有一个 I/O 操作完成,并将完成的信息填充到相应的变量中,包括传输的字节数dwTrans、与套接字相关的结构体指针pPerHandle和与 I/O 操作相关的结构体指针pPerIO
1 | BOOL GetQueuedCompletionStatus( |
3.WSARecv函数
1 | int WSARecv( |

4.WSASend函数
1 | int WSASend( |
5.个人课程作业附代码
作业4:基于IOCP模型编写可伸缩网络通信服务器程序。描述如下:
(1)基于IOCP模型,要求给完成端口指定的并发线程数量= CPU核数+2,业务服务线程数=1;
(2)数据包采用c结构体:
struct send_packet
{
byte len; //结构体长度,也就是包长度
byte type ; //协议类型
byte cmd; //命令码
char data[64]; //数据
};
(3)自动分包机制;
(4)服务端套接字收到客户端发来的数据后,保存到磁盘文件,文件名:file_日期.txt,如:file_2024-09-29.txt,然后向客户端回应消息,结构如下:
struct response_packet
{
byte len; //结构体长度,也就是包长度
byte err ; //大于0:成功, 小于0:失败
char msg[32]; //返回消息描述
};
(5)要求开发语言C++
Init.h文件:
1 |
|
Server.cpp
1 |
|
5.个人课程作业附代码
效果展示:



Init.h文件:
1 |
|
Server.cpp
1 |
|