[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(Input Output Completion Port)输入输出完成端口。其实就是基于重叠I/O的一种改进的模型。 重叠I/O具有缺点:重复调用非阻塞模式的accpet函数和以进入alertablewait状态为目的的SleepEx函数会影响程序性能。 而IOCP提供…...

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

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

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

LeetCode 1251. 平均售价
题目链接:1251. 平均售价 题目描述 表:Prices Column NameTypeproduct_idintstart_datedateend_datedatepriceint (product_id,start_date,end_date) 是 prices 表的主键(具有唯一值的列的组合)。 price…...

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

蓝牙技术|Matter或能改变中国智能家居市场,蓝牙技术将得到进一步应用
近年来,智能家居开放协议标准Matter(目前版本 1.1)由连接标准联盟发布,该联盟是一个由数百家公司组成的全球性机构,旨在提供与物联网 (IoT) 相关的标准。例如,Matter 用于允许 Amazon Alexa、Apple Home、G…...

VB.NET vs. VB6.0:现代化编程语言 VS 经典老旧语言
目录 .NET背景: 特点: VB6.0背景: 特点: 两者之间的不同: 总结: 升华: .NET背景: VB.NET一种简单,现代,面向对象计算机编程语言,有微软开发,VB.NET是一种基于.NET Framework的面向对象…...

ViewPager、RecycleView实现轮播图
1.ViewPager实现轮播图形效果。 1)layout中,PageIndicatorView轮播的View <RelativeLayoutandroid:layout_width"match_parent"android:layout_height"200dp"android:orientation"vertical"><androidx.viewpager…...

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

【PPT】ppt里面使用svg图标
要想编辑好的PPT,少不了小图标的美化,图标可以使PPT变得更有趣,更易懂,更美观。 对于png,主要处理它的颜色,可使用【重新着色】功能。 对于jpg,主要处理它的背景,删除背景后同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来完成,比如说以下这张表 用户一次签到,就是一条记录,假如有1000万用户,平均每人每年签到次数为10次,则这张表一年的数据量为 1亿条 每签到一次需要使用(…...
作为创始人的价值观与心法,构建系统
价值观 绿色、健康、有趣、感恩、谦卑、责任、勇气、客观、冷静、自洽、尊重、价值、服务、善良、利他 作为co-founder衡量的一个很重要的标准就是这个人的人品,大家一起做事情的体验要好,才能有large energy,且流通。 乐观、通达…...
Go语言基础面经
1.go语言编程的好处是什么 编译和运行都很快。 在语言层级支持并行操作。 有垃圾处理器。 内置字符串和 maps。 函数是 go 语言的最基本编程单位。 2.说说go语言的select机制 select 机制用来处理异步 IO 问题 select 机制最大的一条限制就是每个 case 语句里必须是一个…...

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

剑指offer——JZ68 二叉搜索树的最近公共祖先 解题思路与具体代码【C++】
一、题目描述与要求 二叉搜索树的最近公共祖先_牛客题霸_牛客网 (nowcoder.com) 题目描述 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 1.对于该题的最近的公共祖先定义:对于有根树T的两个节点p、q,最近公共祖先LCA(T,p,q)表示一个节点x&#…...

[Spring] @Bean 修饰方法时如何注入参数
目录 一、Bean 的简单使用 1、正常情况 2、问题提出 二、解决方案 1、Qualifier 2、直接写方法名 三、特殊情况 1、DataSource 一、Bean 的简单使用 在开发中,基于 XML 文件配置 Bean 对象的做法非常繁琐且不好维护,因此绝大部分情况下都是使用…...
docker拉取镜像错误 missing signature key
您正在尝试使用 yum 在 CentOS 或 RHEL 系统上安装 docker-ce,但您遇到了一些问题。根据您提供的输出,这里有几个需要注意的点: 系统未注册: "This system is not registered with an entitlement server" 指示您的系统未注册。对于…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...