IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> IOCP完成端口通俗讲义与项目实战 -> 正文阅读

[网络协议]IOCP完成端口通俗讲义与项目实战

什么是IOCP完成端口?

我们可以把IOCP完成端口(以下统称IOCP)理解为Windows下性能最高的网络编程技术,本文讲解该技术的基本知识,以及如何使用该技术开发高性能的网络软件。
IOCP本质上就是Windows内核提供的一种请求队列+通知队列,我们把各种耗时的网络操作请求投递到请求队列,IOCP具体怎么去完成这些网络操作我们不管,IOCP完成后会把结果放到通知队列里,我们就去通知队列里获取结果然后处理。

什么是同步和异步?

同步就是,你跟朋友聊天,你发完一句话后,一直盯着这个聊天窗口等待朋友回复,这样你就只能同时跟一个朋友聊天。如果有10个朋友同时找你,要么你就只能让后面9个朋友排队等着,等你跟第一个朋友聊完了再聊下一个,要么就需要再请9个人帮你聊天。
异步就是,你跟朋友聊天,你发完一句话后,就去做其他事情,等听到消息通知后,再去回复朋友。这样即使10个朋友同时找你,你一个人也能聊得过来。所以异步的效率是不是比同步高很多?
我们最开始接触网络编程时,一般都是用同步模式。比如我要发起TCP连接,就会调用connect函数,调用过程中会阻塞等待,直到连接成功或者失败才会返回,然后判断函数的返回值。这就是同步模式,最简单但是效率也最低。
IOCP是一种异步模式,我调用connect函数后,调用会马上返回而且没有结果。我就可以先去执行其他任务,直到我得到通知说connect请求已经有结果了,我才去处理。

IOCP的使用步骤

虽然要完全掌握IOCP比较难,但它的使用步骤其实非常简单,关键就这么几步:创建IOCP关联SOCKET投递网络操作请求获取IO通知。我们以发起TCP连接为例,详细讲解这些步骤。

1.创建IOCP

我们先使用WSAStartup启动套接字库。

WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);

然后我们创建一个IOCP实例,后续的操作将使用这个实例的句柄。

HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

2.关联SOCKET

进行网络操作肯定要先创建SOCKET,但跟平时不同的是,我们需要创建一个支持异步模式的特殊SOCKET,即给SOCKET加上重叠标志WSA_FLAG_OVERLAPPED

SOCKET socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);

然后我们把这个SOCKET关联到IOCP中去,这样以后对该SOCKET发起的网络操作都会由IOCP处理。

CreateIoCompletionPort((HANDLE)socket, hIOCP, socket, 0);

3.投递网络操作请求

每个投递到IOCP中的请求都需要包含一个编号信息,IOCP完成请求后在通知里也会包含这个编号信息。通过这个编号信息才能知道哪个通知对应哪个请求,这个编号信息就保存在重叠结构里。
我们不能调用普通的connect函数来发起连接,而是需要调用一个支持重叠结构的ConnectEx函数。但是这个函数默认是没有加载的,我们需要先加载这个函数。

GUID guidConn = WSAID_CONNECTEX;
LPFN_CONNECTEX pfnConnectEx = NULL;
DWORD dw = 0;
WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidConn, sizeof(guidConn), &pfnConnectEx, sizeof(pfnConnectEx), &dw, NULL, NULL);

跟调用connect函数发起连接不同的是,调用ConnextEx函数发起连接前,需要先把SOCKET绑定好本地端口。我们可以绑定0,这样系统就会自动分配本地端口。

sockaddr_in addrBind = {0};
addrBind.sin_family = AF_INET;
addrBind.sin_addr.s_addr = htonl(INADDR_ANY);
addrBind.sin_port = htons(0);
bind(socket ,(SOCKADDR *)&addrBind, sizeof(addrBind));

然后调用ConnectEx函数发起连接,注意最后一个参数就是重叠结构。这时连接请求和相应的重叠结构,就一起投递到IOCP里去了。

sockaddr_in addrConn = {0};
addrConn.sin_family = AF_INET;
addrConn.sin_addr.S_un.S_addr = inet_addr("112.53.42.52");
addrConn.sin_port = htons(80);
OVERLAPPED overlap = {0};
pfnConnectEx(socket, (sockaddr*)&addrConn, sizeof(addrConn), NULL, 0, NULL, &overlap);

4.获取IO通知

最后我们向IOCP获取通知,如果IOCP通知队列里暂时还没有通知,则会阻塞等待。

DWORD dwBytes;
SOCKET socketGet;
OVERLAPPED* overlapGet;
BOOL bIOSucc = GetQueuedCompletionStatus(hIOCP, &dwBytes, (PULONG_PTR)&socketGet, (LPOVERLAPPED*)&overlapGet, INFINITE);

获取到通知后,我们可以根据bIOSucc来判断是否连接成功,其他参数怎样使用,我们后续再详细讲解。

(未完待续)

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 16:25:55  更:2022-04-06 16:28:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:36:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码