IOCP小结

article/2025/11/8 7:26:40

文章目录

  • 一 什么是完成端口(completion port)对象
  • 二 使用IOCP的方法
    • 创建完成端口对象
    • I/O服务线程和完成端口
    • 完成端口和重叠I/O
  • 三 恰当地关闭IOCP
  • 四 IOCP大概的处理流程
  • 五 一个简单示例具体编程流程

当应用程序必须一次管理多个套接字时,完成端口模型提供了最好的系统性能。这个模型也提供了最好的伸缩性,它非常适合用来处理上百上千个套接字。

IOCP模型是事先开好了N个线程,存储在线程池中,让他们hold。然后将所有用户的请求都投递到一个完成端口上,然后N个工作线程逐一地从完成端口中取得用户消息并加以处理。这样就避免了为每个用户开一个线程。既减少了线程资源,又提高了线程的利用率。

一 什么是完成端口(completion port)对象

I/O完成端口是应用程序使用线程池处理异步I/O请求的一种机制。处理多个并发异步I/O请求时,使用I/O完成端口比在I/O请求时创建线程更快更有效。

二 使用IOCP的方法

创建完成端口对象

使用完成端口模型,首先要调用CreateIoCompletionPort函数创建一个完成端口对象,Winsock将使用这个对象为任意数量的套接字句柄管理I/O请求。函数定义如下:

HANDLE CreateIoCompletionPort(  HANDLE hFile,                          //要关联的套接字句柄HANDLE hExistingCompletionPort,         //创建的完成端口对象句柄ULONG_PTR CompletionKey,        //制定一个句柄唯一数据,它将与套接字句柄关联在一起。应用程序可以在此存储任意类型的信息,通常是一个指针DWORD dwNumberOfConcurrentThreads   //允许在完成端口上同时执行的线程的数量);  

此函数有两个不同的功能:
1 创建一个完成端口对象;
2 将一个或多个文件句柄(套接字句柄)关联到I/O完成端口对象

I/O服务线程和完成端口

成功创建完成端口对象之后,就可以向这个完成端口对象关联套接字句柄了。在关联套接字之前,需要先创建一个或多个工作线程(成为I/O服务线程),在完成端口上执行并处理投递到完成端口上的I/O请求。

有了足够的工作线程来处理完成端口上的I/O请求后,就该为完成端口关联套接字句柄,这使用到了CreateIoCompletionPort的前三个参数。CompletionKey参数通常用来描述与套接字相关的信息,所以称它为句柄唯一(per=handle)数据。

完成端口和重叠I/O

在完成端口关联套接字句柄之后,便可以通过在套接字上投递重叠发送和接收请求处理I/O了。这些I/O操作完成时,I/O系统会向完成端口对象发送一个完成通知封包。

I/O完成端口以先进先出的方式为这些封包排队。应用程序使用GetQueuedCompletionSatus函数可以取得这些队列中的封包。这个函数应该在处理完成端口对象I/O的服务线程中调用。

GetQueuedCompletionStatus(HANDLE CompletionPort,            //完成端口对象句柄LPDWORD lpNumberOfBytes      	    //取得I/O操作期间传输的字节数PULONG_PTR lpCompletionKey, 	    //取得在关联套接字时指定的句柄唯一数据(指针)LPOVERLAPPED* lpOverlapped,      //取得投递I/O操作时指定的OVERLAPPED 结构DWORD dwMilliseconds            //如果完成端口没有完成封包,此参数指定了等待的事件,INFINIE为无穷大)

I/O服务线程调用GetQueuedCompletionStatus函数取得有事件发生的套接字的信息,通过lpNumberOfBytes参数得到传输的字节数量,通过lpCompletionKey参数得到与套接字关联的句柄唯一(per-handle)数据,通过lpOverlapped参数得到投递I/O请求时使用的重叠对象地址,进一步得到I/O唯一(per-I/O)数据。

lpCompletionKey参数包含了我们称为per-Handle的数据,因为当套接字第一次与完成端口关联时,这个数据就关联到一个套接字句柄。这是传递给CreateIoCompletionPort函数的CompletionKey参数。

lpOverlapped参数指向一个OVERLAPPED结构,结构后面便是我们称为per-I/O的数据,这可以是工作线程处理完成封包时想要知道的任何信息。

三 恰当地关闭IOCP

四 IOCP大概的处理流程

1 创建一个完成端口
2 创建一个线程A
3 A线程循环调用GetQueuedCompletionStatus()函数来得到IO操作结果
4 主线程循环里调用accept等待客户端连接
5 主线程里accept返回新连接后,把这个新的套接字句柄用CreateIoCompletionPort()关联到完成端口,然后发出一个异步WSASend或者WSARecv调用,因为是异步函数,WSASend/WSARecv会马上返回,实际的发送或者接收操作由Windows系统去做。
6 主线程继续下一次循环,阻塞在accept这里等待新的客户连接
7 Windows系统完成WSASend或者WSARecv的操作,把结果发到完成端口。
8 A线程里的GetQueuedCompletionStatus()马上返回,并从完成端口取得刚完成的WSASend/WSARecv的结果。
9 在A线程里对这些数据进行处理(如果处理过程很耗时,需要新开线程处理),然后紧接着发出WSASend/WSARecv,并继续下一次循环阻塞在GetQueuedCompletionStatus()这里。

流程图:

在这里插入图片描述
上述流程中有两种类型的线程 —主线程和它创建的线程,主线程创建监听套接字,创建额外的工作线程,关联IOCP,负责等待和接受到来的连接等;由主线程创建的线程负责处理I/O事件,这些线程调用GetQueuedCompletionStatus函数在完成端口对象上等待完成的I/O操作。

五 一个简单示例具体编程流程

1 创建一个完成端口对象,创建一个或多个服务线程,服务线程调用GetQueuedCompletionStatus取得完成I/O通知信息。主线程接收连接,将新套接字关联到完成端口上,然后在新连接上投递Read I/O异步请求。

2 服务线程从GetQueuedCompletionStatus函数返回后,根据per-handle I/O数据中的信息,做出相应的处理,并继续投递下一个Read I/O异步请求。

#define _WIN32_WINNT 0x0400   #include<windows.h>
#include<cstdio>
#include"InitSocket.h"#define BUFFER_SIZE 2048CInitSock initSock ; //进入main函数前已经进行了初始化typedef	struct _PER_HANDLE_DATA			//per-handle数据
{SOCKET s ;							//对应的套接字句柄sockaddr_in addr ;					//客户方地址
}  PER_HANDLE_DATA ,*PPER_HANDLE_DATA ;/********************************************************/
//包含版本
typedef	struct _PER_IO_DATA		//per-I/O数据
{OVERLAPPED ol ;				//重叠结构,必须放作第一个结构,用C++派生的方法更好char buf[BUFFER_SIZE] ;		//数据缓冲区int nOperationType ;		//操作类型#define	OP_READ 1				//操作类型码
#define	OP_WRITE 2
#define	OP_ACCEPT 3
} PER_IO_DATA,*PPER_IO_DATA ;
/**********************************************************//************************************************************ 派生版本的
class _PER_IO_DATA : public OVERLAPPED
{public :char buf[BUFFER_SIZE] ;int nOperationType ;
#define	OP_READ 1				//操作类型码
#define	OP_WRITE 2
#define	OP_ACCEPT 3
} ;
typedef	 _PER_IO_DATA PER_IO_DATA ;
typedef	PER_IO_DATA *PPER_IO_DATA;
***************************************************/DWORD WINAPI ServerThread(LPVOID lpParam)  ;int main(void)
{int nPort = 4567 ;//创建完成端口对象,创建工作线程处理完成端口对象中的事件HANDLE hCompletion = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0) ;CreateThread(NULL,0,ServerThread,(LPVOID)hCompletion,0,0) ;//创建监听套接字,绑定到本地地址,开始监听SOCKET sListen = socket(AF_INET,SOCK_STREAM,0) ;SOCKADDR_IN si ;si.sin_family = AF_INET ;si.sin_port = ntohs(nPort) ;si.sin_addr.s_addr = INADDR_ANY ;bind(sListen,(sockaddr*)&si,sizeof(si)) ;listen(sListen,5) ;//循环处理到来的连接while(TRUE){//等待接受未决的连接请求SOCKADDR_IN saRemote ;int nRemoteLen = sizeof(saRemote) ;SOCKET sNew = accept(sListen,(sockaddr*)&saRemote,&nRemoteLen) ;//接受到新连接之后,为创建一个per-handle数据,并将它们关联到完成端口对象PPER_HANDLE_DATA pPerHandle = (PPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA)) ;pPerHandle->s = sNew ;memcpy(&pPerHandle->addr,&saRemote,nRemoteLen) ;CreateIoCompletionPort((HANDLE)pPerHandle->s,hCompletion,(DWORD)pPerHandle,0) ; //关联,不是创建.涉及到转型,将指针转为DWORD,与pPerHandle->s关联的唯一数据就是PerHandle//投递一个接收请求PPER_IO_DATA pPerIO = (PPER_IO_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_DATA)) ;pPerIO->nOperationType = OP_READ ;WSABUF buf ;buf.buf = pPerIO->buf ;buf.len = BUFFER_SIZE ;DWORD dwRecv ;DWORD dwFlags = 0 ;//作为引子的接收请求,引发接收操作//与该套接字相关的OVERLAPPED结构WSARecv(pPerHandle->s,&buf,1,&dwRecv,&dwFlags,&pPerIO->ol,NULL) ; }return 0 ;
}//服务线程
DWORD WINAPI ServerThread(LPVOID lpParam) 
{//得到完成端口对象句柄`HANDLE hCompletion = (HANDLE)lpParam ;DWORD dwTrans ;PPER_HANDLE_DATA pPerHandle ;PPER_IO_DATA pPerIO ;while(TRUE){//在关联到此完成端口的所有套接字上等待I/O完成,倒数第二个参数的作法其实是非常不适当的BOOL bOK = GetQueuedCompletionStatus(hCompletion,&dwTrans,(LPDWORD)&pPerHandle,(LPOVERLAPPED*)&pPerIO,WSA_INFINITE) ;if(!bOK) //在此套接字上有错误发生{closesocket(pPerHandle->s) ;	GlobalFree(pPerHandle) ;GlobalFree(pPerIO) ;continue ;}//套接字被对方关闭if(dwTrans == 0 && (pPerIO->nOperationType == OP_READ || pPerIO->nOperationType == OP_WRITE)){closesocket(pPerHandle->s) ;GlobalFree(pPerHandle) ;GlobalFree(pPerIO) ;continue ;}switch(pPerIO->nOperationType)		//通过per-I/O数据中的nOperationType域查看什么I/O请求完成了{case OP_READ : //完成一个接收请求{pPerIO->buf[dwTrans] = '\0' ;printf(pPerIO->buf) ;//继续投递接收I/O请求WSABUF buf ;buf.buf = pPerIO->buf ;buf.len = BUFFER_SIZE ;pPerIO->nOperationType = OP_READ ;DWORD nFlags = 0 ;WSARecv(pPerHandle->s,&buf,1,&dwTrans,&nFlags,&pPerIO->ol,NULL) ; //继续引发在该套接字上面的接收操作//投递一个发送请求I/O,我自己添加,为了测试OR_WRITE之用PPER_IO_DATA pSendPerIO = (PPER_IO_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_DATA)) ;pSendPerIO->nOperationType = OP_WRITE ;memcpy(pSendPerIO->buf,pPerIO->buf,dwTrans) ;WSABUF dbuf ;dbuf.buf = pSendPerIO->buf ;dbuf.len = dwTrans ;           //如果大于客户端的接收缓冲区,则客户端需要重复多次recv才能接收完所有数据WSASend(pPerHandle->s,&dbuf,1,&dwTrans,nFlags,&pSendPerIO->ol,NULL); //引发在该套接字上面的发送操作} break ;case OP_WRITE :{printf("发送数据完成\n");}break ;case OP_ACCEPT : //这个多余的,因为主线程因为在accpet了break ;}}return 0 ;
}

http://chatgpt.dhexx.cn/article/0U7jN1Vl.shtml

相关文章

IOCP高性能服务器的实现

应用场景说明&#xff1a;完成端口在面向现实应用的许多网络通信中应用很广泛&#xff0c;例如大型多人在线游戏&#xff0c;大型即时通信系统&#xff0c;网吧管理系统以及企业管理系统等具有大量并发用户请求的场合。 实现目标说明&#xff1a;通过完成端口模型构建一款服务…

IOCP 详解

IOCP 详解 网络上关于epoll的介绍资料多如牛毛&#xff0c;大多数已经讲解的非常细致。相比而言epoll只有三个接口调用&#xff0c;IOCP却有一堆的接口调用&#xff0c;更关键的是Windows的闭源性质&#xff0c;我们不知道调用之后Windows究竟做了哪些操作。众所周知IOCP是基于…

IOCP简介

1.1 环境要求本文读者需要熟悉C、TCP/IP、Socket编程、MFC&#xff0c;和多线程。源码使用Winsock 2.0和IOCP技术&#xff0c;要求&#xff1a;Windows NT/2000或以上&#xff1a;要求Windows NT3.5或以后版本Windows 95/98/ME&#xff1a;不支持Visual C.NET&#xff0c;或完整…

什么是IOCP

百度词条 输入输出完成端口&#xff08;Input/Output Completion Port&#xff0c;IOCP&#xff09;, 是支持多个同时发生的异步I/O操作的应用程序编程接口 一个IOCP对象&#xff0c;在操作系统中可关联着多个Socket和&#xff08;或&#xff09;文件控制端。 IOCP对象内部有一…

IOCP

载自&#xff1a;http://blog.csdn.net/markman101/article/details/6235516 本文主要探讨一下windows平台上的完成端口开发及其与之相关的几个重要的技术概念&#xff0c;这些概念都是与基于IOCP的开发密切相关的&#xff0c;对开发人员来讲&#xff0c;又不得不给予足够重视的…

IOCP模型与网络编程

IOCP模型与网络编程 一。前言&#xff1a; 在老师分配任务&#xff08;“尝试利用IOCP模型写出服务端和客户端的代码”&#xff09;给我时&#xff0c;脑子一片空白&#xff0c;并不知道什么是IOCP模型&#xff0c;会不会是像软件设计模式里面的工厂模式&#xff0c;装…

Windows下的IOCP模型(一):介绍与简单使用

一、IOCP简介 IOCP&#xff08;I/O Completion Port&#xff0c;I/O完成端口&#xff09;是Windows操作系统中伸缩性最好的一种I/O模型。I/O 完成端口是应用程序使用线程池处理异步 I/O 请求的一种机制。处理多个并发异步I/O请求时&#xff0c;使用 I/O 完成端口比在 I/O 请求时…

完成端口(IOCP)编程探讨

FW: http://www.zhuaxia.com/item/473350387 完成端口(IOCP)编程探讨 2007-08-26 16:06:00 来自&#xff1a;C博客-首页原创精华区 新建目录...根目录新手试用频道 本文主要探讨一下windows平台上的完成端口开发及其与之相关的几个重要的技术概念&#xff0c;这些概念都是与…

异步通信之IOCP详解

一、 概述 学习完网络基础&#xff0c;在写C/S应用程序时&#xff0c;大多童靴写服务器基本都没有用到io模型&#xff0c;基本都是采用“accept同步拥塞通讯和多线程方式”与客户端通讯。但当有成千上万客户端请求连接并与服务器通讯时&#xff0c;多线程的创建与CPU上下文的切…

IOCP详解

IOCP详解 IOCP&#xff08;I/O Completion Port&#xff0c;I/O完成端口&#xff09;是性能最好的一种I/O模型。它是应用程序使用线程池处理异步I/O请求的一种机制。在处理多个并发的异步I/O请求时&#xff0c;以往的模型都是在接收请求是创建一个线程来应答请求。这样就有很多…

IOCP技术详解

这几周我接触了Windows网络通讯中的IOCP模型,自己在网上找了相关的知识进行学习&#xff0c;自己又下了好多服务器端的代码&#xff0c;但都运行不了&#xff0c;也是自己菜&#xff0c;能力还需加强。幸好我师父资助了我一个能运行的服务端IOCP代码&#xff0c;自己参照网上的…

Python正则表达式模式

在 Python 程序中&#xff0c;模式字符串使用如下特殊的语法来表示一个正则表达式&#xff1a; 字母和数字表示它们自身&#xff0c;一个正则表达式模式中的字母和数字匹配同样的字符串&#xff1b;当大多数字母和数字前加一个反斜杠时&#xff0c;它们会拥有不同的含义&#…

Python正则表达式实例详解

一、正则表达式语法 正则表达式是用匹配或者描述字符串的工具。 用处&#xff1a; a.判断字符串是否满足某个条件—判断输入的字符串是否是邮箱/手机号码。是否是ip地址 b.提取满足条件的字符串 c.字符串替换 Python中通过re模块中相应的方法来支持正则表达式的匹配、查找和替…

Python正则表达式语法快速入门

文章目录 1 正则符号初阶代码举例1&#xff1a;不同符号的组合代码举例2&#xff1a;符号加&#xff0c;代表连续的一个或多个代码举例3&#xff1a;匹配字符串开始代码举例4&#xff1a;匹配字符串结束代码举例5&#xff1a;匹配单词边界 2 正则符号进阶代码举例1&#xff1a;…

python正则表达式入门

&#x1f64a;今天我们来学习python的正则表达式的部分&#xff0c;先说下为什么要学习这一部分呢&#xff0c;当然是因为正则表达式处理文本类型的数据实在是太方便了。为以后进入nlp领域打打基础&#xff01; 先给大家推荐一个网站: 用于正则表达式验证. 大致就长这个样子。…

python使用正则表达式

一、使用正则表达式步骤 1、寻找规律&#xff1b; 2、使用正则符号表示规律&#xff1b; 3、提取信息&#xff0c;如果每一个字符都能匹配&#xff0c;则匹配成功&#xff1b;一旦有匹配不成功的字符则匹配失败。 二、正则表达式中常见的基本符号 1&#xff0e;点号“.”一…

Python 正则表达式

1.正则表达式的定义: 正则表达式是对字符串进行解析&#xff08;获取一大串字符串信息中&#xff0c;你想要的部分&#xff09;。 正则表达式是一种文本模式&#xff0c;模式描述在搜索文本时要匹配的一个或多个字符串。 正则表达式&#xff0c;又成正规表示式&#xff0c;正规…

python正则表达式详解

正则表达式是一个很强大的字符串处理工具&#xff0c;几乎任何关于字符串的操作都可以使用正则表达式来完成&#xff0c;作为一个爬虫工作者&#xff0c;每天和字符串打交道&#xff0c;正则表达式更是不可或缺的技能&#xff0c;正则表达式的在不同的语言中使用方式可能不一样…

详解Python正则表达式(含丰富案例)

前言&#xff1a;正则表达式在网络爬虫、数据分析中有着广泛使用&#xff0c;掌握正则表达式能够达到事半功倍的效果。本文详细介绍正则表达式中各种规则及其符号含义&#xff0c;并结合Python中的Re库进行演示&#xff0c;由浅入深&#xff0c;即学即练即用&#xff0c;内容丰…

Python超详细的正则表达式

目录 介绍 常用的正则表达式匹配规则表格 1.match() .group() 常用知识点 1.通用匹配 2.贪婪与非贪婪 3.修饰符 4.转义匹配 2.search() 3.findall() 4.sub() 总结 Hello大家好我是&#xff0c;PYmili&#xff01;今天给大家带来正则表达式的使用教程即匹配规则表格…