当前位置: 首页 > news >正文

[C++ 网络协议] IOCP(Input Output Completion Port)

1.什么是IOCP

IOCP(Input Output Completion Port)输入输出完成端口。其实就是基于重叠I/O的一种改进的模型。

重叠I/O具有缺点:重复调用非阻塞模式的accpet函数和以进入alertablewait状态为目的的SleepEx函数会影响程序性能

而IOCP提供的解决方案便是:让主线程调用accept函数,单独创建至少一个线程来负责所有I/O的前后处理

但请不要过分关注在线程上,主要还是如下问题:

        1.I/O是否以非阻塞模式工作?

        2.如何确定非阻塞模式的I/O是否完成?

2.分阶段实现IOCP程序

2.1 实现原理

IOCP会将已完成的I/O信息注册到CP对象(Completion Port完成端口),而我们就可以通过CP对象来获取I/O是否完成的信息,所以有下面两项工作:

  • 创建完成端口对象
  • 建立完成端口对象和套接字之间的联系 

此时的套接字必须赋予重叠属性。

2.2 创建CP对象

#include<windows.h>HANDLE CreateIoCompletionPort(
HANDLE fileHandle,                //创建CP对象时传递INVALID_HANDLE_VALUE
HANDLE ExistingCompletionPort,    //创建CP对象时传递NULL
ULONG_PTR CompletionKey,          //创建CP对象时传递0
DWORD NumberOfConcurrentThreads   //分配给CP对象的用于处理I/O的线程数。//例如:该参数为2时,说明分配给CP对象的可以同时运行的线程数最多为2个//如果为0时,那么系统中CPU的个数就是可同时运行的最大线程数
);
成功返回CP对象句柄
失败返回NULL

2.3 创建和套接字连接完成的端口对象

#include<windows.h>HANDLE CreateIoCompletionPort(
HANDLE FileHandle,                //要连接到CP对象的套接字句柄
HANDLE ExistingCompletionPort,    //要连接套接字的CP对象句柄
ULONG_PTR CompletionKey,          //传递已完成I/O相关信息
DWORD NumberOfConcurrentThreads   //无论传递何值,只要第二个参数非NULL就会被忽略
);
成功返回CP对象句柄
失败返回NULL

函数功能:将FileHandle句柄指向的套接字和ExistingCompletionPort指向的CP对象相连。

调用此函数后:只要针对FileHandle的I/O完成,相关信息就会注册到ExistingCompletionPort里。

注意:第三个参数“传递已完成I/O相关信息”的意思是,你可以像重叠I/O里使用Complition routine来确认I/O方式里把相关信息填写到hEvent里的那样,写入其他信息,这样当I/O完成就可以获取了。

2.4 确认完成端口已完成的I/O和线程I/O处理

#include<windows.h>BOOL GetQueuedCompletionStatus(
HANDLE CompletionPort,        //注册有已完成I/O信息的CP对象句柄
LPDWORD lpNumberOfBytes,      //保存I/O过程中传输的数据大小的变量地址值
PULONG_PTR lpCompletionKey,   //保存CreateIoCompleytionPort函数第三个参数值得变量地址值
LPOVERLAPPED* lpOverlapped,   //保存调用WSASend、WSARecv函数时传递的OVERLAPPED结构体地址的变量地址值
DWORD dwMilliseconds          //超时信息,超过该指定时间后将返回FALSE并跳出函数。//传递INFINITE时,程序将阻塞,直到已完成I/O信息写入CP对象
);
成功返回TRUE
失败返回FALSE

注意:

  • 调用此函数的线程数量不能超过CreateIoCompletionPort时指定的线程数。
  • 此函数并不知道当前是输入信息状态还是输出信息状态,需要自行判断。

3. 实现IOCP模型的回声服务器端

思路:每连接一个客户端就创建一个线程,然后主线程里先接收一次数据,在子线程里通过GetQueuedCompletionStatus函数阻塞住线程,判断I/O状态,接着把接收的数据发送给客户端,再次进入接收状态,如此循环通信。

变量:

struct ClientInfo结构体:存有套接字和套接字地址族信息,在CreateIoCompletionPort函数里,建立套接字和CP的连接的时候,当做第三参数传入

struct CPInfo结构体:存有一个OVERLAPPED、WSABUF信息,以及还有一个int型用来判断当前是RECV还是SEND,在执行WSARecv函数时当做第六个参数进行传入。运用下面的知识点,所以可以在子线程执行GetQueuedCompletionStatus函数时,取得的第一个成员的地址,也就是这整个结构体的地址。

知识点:结构体变量地址值与结构体第一个成员的地址值相同。

struct CPInfo
{OVERLAPPED overlapped;WSABUF wsabuf;int mode;			//0:RECV 1:SEND
};
CPInfo data;
if(&data==&data.overlapped)
{std::cout<<"TRUE"<<std::endl;
}
else
{std::cout<<"FALSE"<<std::endl;
}
输出TRUE
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
#include<WinSock2.h>
#include<process.h>
#include<Windows.h>
#include<malloc.h>
#include<string>struct ClientInfo
{SOCKET socket;sockaddr_in socketAddr;
};struct CPInfo
{OVERLAPPED overlapped;WSABUF wsabuf;int mode;			//0:RECV 1:SEND
};unsigned WINAPI threadClient(void* arg);int main()
{WSADATA wsaData;if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)){std::cout << "start up fail!" << std::endl;return 0;}SOCKET server = WSASocket(PF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);if (server == INVALID_SOCKET){std::cout << "socket fail!" << std::endl;return 0;}int mode = 1;ioctlsocket(server, FIONBIO, (u_long*)&mode);sockaddr_in serverAddr;memset(&serverAddr, 0, sizeof(serverAddr));serverAddr.sin_family = AF_INET;serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);serverAddr.sin_port = htons(9130);if (SOCKET_ERROR == bind(server, (sockaddr*)&serverAddr, sizeof(serverAddr))){std::cout << "bind fail!" << std::endl;return 0;}if (SOCKET_ERROR == listen(server, 2)){std::cout << "listen fail!" << std::endl;return 0;}while (true){sockaddr_in clientAddr;memset(&clientAddr, 0, sizeof(clientAddr));int clientAddrLen = sizeof(clientAddr);SOCKET client = accept(server, (sockaddr*)&clientAddr, &clientAddrLen);if (client == SOCKET_ERROR){if (WSAGetLastError() == WSAEWOULDBLOCK)	//说明此时没有客户端连接{continue;}std::cout << "accept fail!" << std::endl;}else{HANDLE cpObject = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);if (cpObject == NULL){std::cout << "Create CP fail!" << std::endl;continue;}ClientInfo* clientinfo = new ClientInfo();clientinfo->socket = client;clientinfo->socketAddr = clientAddr;CreateIoCompletionPort((HANDLE)client, cpObject, (ULONG_PTR)clientinfo, 0);unsigned threadId;if (0 == _beginthreadex(NULL, 0, threadClient, (void*)&cpObject, 0, &threadId))	//创建一个线程{std::cout << "thread create fail!" << std::endl;continue;}CPInfo* cpinfo = new CPInfo();cpinfo->mode = 0;memset(&cpinfo->overlapped, 0, sizeof(cpinfo->overlapped));char buff[1024];cpinfo->wsabuf.buf = buff;cpinfo->wsabuf.len = sizeof(buff);DWORD readLen;DWORD flag = 0;WSARecv(client, &cpinfo->wsabuf, 1, &readLen, &flag, &cpinfo->overlapped, NULL);}}closesocket(server);WSACleanup();
}unsigned WINAPI threadClient(void* arg)
{HANDLE cpObject = *(HANDLE*)arg;CPInfo* cpinfo;ClientInfo* clientinfo;while (true){DWORD readLen;GetQueuedCompletionStatus(cpObject, &readLen, (PULONG_PTR)&clientinfo, (LPOVERLAPPED*)&cpinfo, INFINITE);if (readLen == 0){std::cout << "客户端:" << inet_ntoa(clientinfo->socketAddr.sin_addr) << "断开连接!" << std::endl;break;}if (cpinfo->mode == 0)		//recv{std::cout << "客户端发来的消息:" << cpinfo->wsabuf.buf << std::endl;DWORD flag = 0;cpinfo->mode = 1;WSASend(clientinfo->socket, &cpinfo->wsabuf, 1, &readLen, flag, &cpinfo->overlapped, NULL);CPInfo* cpinfo2 = new CPInfo();cpinfo2->mode = 0;memset(&cpinfo2->overlapped, 0, sizeof(cpinfo2->overlapped));char buff[1024];cpinfo2->wsabuf.buf = buff;cpinfo2->wsabuf.len = sizeof(buff);DWORD readLen2;WSARecv(clientinfo->socket, &cpinfo2->wsabuf, 1, &readLen2, &flag, &cpinfo2->overlapped, NULL);}else						//send{delete cpinfo;}}CloseHandle(cpObject);closesocket(clientinfo->socket);return 0;
}

相关文章:

[C++ 网络协议] IOCP(Input Output Completion Port)

1.什么是IOCP IOCP&#xff08;Input Output Completion Port&#xff09;输入输出完成端口。其实就是基于重叠I/O的一种改进的模型。 重叠I/O具有缺点&#xff1a;重复调用非阻塞模式的accpet函数和以进入alertablewait状态为目的的SleepEx函数会影响程序性能。 而IOCP提供…...

R实现地图相关图形绘制

大家好&#xff0c;我是带我去滑雪&#xff01; 地图相关图形绘制具有许多优点&#xff0c;这些优点使其在各种领域和应用中非常有用。例如&#xff1a;地图相关图形提供了一种直观的方式来可视化数据&#xff0c;使数据更容易理解和分析。通过地图&#xff0c;可以看到数据的空…...

【Jmeter】性能测试脚本开发——性能测试环境准备、Jmeter脚本编写和执行

文章目录 一、常用的Jmeter元件二、性能测试环境准备三、编写Jmeter脚本四、执行测试脚本 一、常用的Jmeter元件 取样器-HTTP请求 作用&#xff1a;发送HTTP请求配置原件-HTTP请求默认值 作用&#xff1a;设置HTTP请求的默认参数配置原件-用户定义的变量 作用&#xff1a;定义…...

看好你家电视盒的后门!数千个Android电视盒感染了与欺诈相关的危险恶意软件

如果你从Android电视盒获得流媒体修复程序&#xff0c;则你的设备可能会被恶意软件所感染&#xff0c;这些恶意软件能够进行广告欺诈、创建假帐户&#xff0c;并通过悄悄地将你的数据转移到中国的服务器来销售对家庭网络的访问。 根据本周的一份新报告&#xff0c;网络安全公司…...

LeetCode 1251. 平均售价

题目链接&#xff1a;1251. 平均售价 题目描述 表&#xff1a;Prices Column NameTypeproduct_idintstart_datedateend_datedatepriceint (product_id&#xff0c;start_date&#xff0c;end_date) 是 prices 表的主键&#xff08;具有唯一值的列的组合&#xff09;。 price…...

TypeScript 笔记:String 字符串

1 对象属性 length 返回字符串的长度 2 对象方法 charAt() 返回在指定位置的字符 charCodeAt() 返回在指定的位置的字符的 Unicode 编码 concat 连接两个或更多的字符串 indexOf 返回某个指定的字符串值在字符串中首次出现的位置 lastIndexOf 从后向前搜索字符串&…...

蓝牙技术|Matter或能改变中国智能家居市场,蓝牙技术将得到进一步应用

近年来&#xff0c;智能家居开放协议标准Matter&#xff08;目前版本 1.1&#xff09;由连接标准联盟发布&#xff0c;该联盟是一个由数百家公司组成的全球性机构&#xff0c;旨在提供与物联网 (IoT) 相关的标准。例如&#xff0c;Matter 用于允许 Amazon Alexa、Apple Home、G…...

VB.NET vs. VB6.0:现代化编程语言 VS 经典老旧语言

目录 ​.NET背景&#xff1a; 特点: VB6.0背景&#xff1a; 特点: 两者之间的不同: 总结: 升华: .NET背景&#xff1a; VB.NET一种简单&#xff0c;现代&#xff0c;面向对象计算机编程语言&#xff0c;有微软开发&#xff0c;VB.NET是一种基于.NET Framework的面向对象…...

ViewPager、RecycleView实现轮播图

1.ViewPager实现轮播图形效果。 1&#xff09;layout中&#xff0c;PageIndicatorView轮播的View <RelativeLayoutandroid:layout_width"match_parent"android:layout_height"200dp"android:orientation"vertical"><androidx.viewpager…...

【FreeRTOS】【STM32】01从零开始的freertos之旅 浏览源码下的文件夹

基于野火以及正点原子 在打开正点原子的资料pdf时&#xff0c;我遇到了pdf无法复制粘贴的问题&#xff0c;这里有个pdf解锁文字复制功能的网址&#xff0c;mark一下。超级pdf 参考资料《STM32F429FreeRTOS开发手册_V1.2》 官方资料 FreeRTOS 的源码和相应的官方书籍均可从官…...

【PPT】ppt里面使用svg图标

要想编辑好的PPT&#xff0c;少不了小图标的美化&#xff0c;图标可以使PPT变得更有趣&#xff0c;更易懂&#xff0c;更美观。 对于png&#xff0c;主要处理它的颜色&#xff0c;可使用【重新着色】功能。 对于jpg&#xff0c;主要处理它的背景&#xff0c;删除背景后同png处…...

uni-app:实现页面效果4(echarts数据可视化)

效果 代码 <template><view><view><view class"title">概况</view><view class"line_position"><view class"line1"><view class"item"><view class"one">今日销售…...

vue实现echarts中 9种 折线图图例

let datas [{ DivideScore: 7, UserScore: 7.2, Name: 目标制定 },{ DivideScore: 7, UserScore: 7, Name: 具体性 },{ DivideScore: 7, UserScore: 7.5, Name: 可衡量性 },{ DivideScore: 7, UserScore: 7, Name: 可实现性 },{ DivideScore: 7, UserScore: 7, Name: 时间限定…...

redis实战-实现用户签到UV统计

BitMap功能演示 我们针对签到功能完全可以通过mysql来完成&#xff0c;比如说以下这张表 用户一次签到&#xff0c;就是一条记录&#xff0c;假如有1000万用户&#xff0c;平均每人每年签到次数为10次&#xff0c;则这张表一年的数据量为 1亿条 每签到一次需要使用&#xff08…...

作为创始人的价值观与心法,构建系统

价值观 绿色、健康、有趣、感恩、谦卑、责任、勇气、客观、冷静、自洽、尊重、价值、服务、善良、利他 作为co-founder衡量的一个很重要的标准就是这个人的人品&#xff0c;大家一起做事情的体验要好&#xff0c;才能有large energy&#xff0c;且流通。 乐观、通达&#xf…...

Go语言基础面经

1.go语言编程的好处是什么 编译和运行都很快。 在语言层级支持并行操作。 有垃圾处理器。 内置字符串和 maps。 函数是 go 语言的最基本编程单位。 2.说说go语言的select机制 select 机制用来处理异步 IO 问题 select 机制最大的一条限制就是每个 case 语句里必须是一个…...

服务器文件备份

服务器上&#xff0c;做好跟应用程序有关的文件备份&#xff08;一般备份到远程的盘符&#xff09;&#xff0c;有助于当服务器发生硬件等故障时&#xff0c;可以对系统进行进行快速恢复。 下面以Windows服务器为例&#xff0c;记录如何做文件的备份操作。 具体操作如下&#…...

剑指offer——JZ68 二叉搜索树的最近公共祖先 解题思路与具体代码【C++】

一、题目描述与要求 二叉搜索树的最近公共祖先_牛客题霸_牛客网 (nowcoder.com) 题目描述 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 1.对于该题的最近的公共祖先定义:对于有根树T的两个节点p、q&#xff0c;最近公共祖先LCA(T,p,q)表示一个节点x&#…...

[Spring] @Bean 修饰方法时如何注入参数

目录 一、Bean 的简单使用 1、正常情况 2、问题提出 二、解决方案 1、Qualifier 2、直接写方法名 三、特殊情况 1、DataSource 一、Bean 的简单使用 在开发中&#xff0c;基于 XML 文件配置 Bean 对象的做法非常繁琐且不好维护&#xff0c;因此绝大部分情况下都是使用…...

docker拉取镜像错误 missing signature key

您正在尝试使用 yum 在 CentOS 或 RHEL 系统上安装 docker-ce&#xff0c;但您遇到了一些问题。根据您提供的输出&#xff0c;这里有几个需要注意的点&#xff1a; 系统未注册: "This system is not registered with an entitlement server" 指示您的系统未注册。对于…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

uni-app学习笔记三十五--扩展组件的安装和使用

由于内置组件不能满足日常开发需要&#xff0c;uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件&#xff0c;需要安装才能使用。 一、安装扩展插件 安装方法&#xff1a; 1.访问uniapp官方文档组件部分&#xff1a;组件使用的入门教程 | uni-app官网 点击左侧…...

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...