见到的一篇IOCP流程 自己用demo实现了一下, 简单照抄,改动了一点点

2023-10-31

要分析的实例分为两个线程:


分别是主线程(MAIN),还有一个是创建的线程(ServerThread)


1.主函数完成初始化工作:
  1.1: (主线程)HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);    创建完成端口对象
  1.2: (主线程)::CreateThread(NULL, 0, ServerThread, (LPVOID)hCompletion, 0, 0);   创建线程用于接收等
  1.3:(主线程)调用socket(),SOCKADDR_IN,bind(),listen(),初始化套接字
  1.4: (线程函数)HANDLE hCompletion = (HANDLE)lpParam;   通过线程参数得到完成端口对象
  1.5: (线程函数) while(TRUE)     定义循环  循环等待套接字上发生事件
  1.6:(线程函数) ::GetQueuedCompletionStatus() 在关联到此完成端口的所有套节字上等待I/O完成
  1.7: (主线程) SOCKADDR_IN saRemote; SOCKET sNew = ::accept(sListen, (sockaddr*)&saRemote, &nRemoteLen); 为新连接建立结构并等待连接请求


2.有连接发生:
  2.1: (主线程while循环中) PPER_HANDLE_DATA pPerHandle = (PPER_HANDLE_DATA)::GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
                           创建PPER_HANDLE_DATA结构 
  2.2: (主线程while循环中) ::CreateIoCompletionPort((HANDLE)pPerHandle->s, hCompletion, (DWORD)pPerHandle, 0);
    完成 完成端口 与 套接字关联
  2.3: (主线程while循环中)    给pPerIO结构   添加类型
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;
  2.4: (主线程while循环中) ::WSARecv(pPerHandle->s, &buf, 1, &dwRecv, &dwFlags, &pPerIO->ol, NULL);     发送异步接收请求
  2.5: (主线程while循环中)  回到WHILE循环accept()函数处  等待新连接
  2.6: (线程函数while循环中)GetQueuedCompletionStatus() 此时I/O完成 开始处理消息
  2.7: (线程函数while循环中)pPerIO->nOperationType  通过类型判断  消息类型
  2.7:(线程函数while循环中)打印接收的消息  并在此投递  一个完成端口
pPerIO->buf[dwTrans] = '\0';
printf(pPerIO -> buf);

WSABUF buf;
buf.buf = pPerIO->buf ;
buf.len = BUFFER_SIZE;
pPerIO->nOperationType = OP_READ;
DWORD nFlags = 0;
printf("12\n");
::WSARecv(pPerHandle->s, &buf, 1, &dwTrans, &nFlags, &pPerIO->ol, NULL);
  2.8:(线程函数while循环中)  由于又有端口I/O完成 ::GetQueuedCompletionStatus()函数  继续判断并处理
  2.9:(线程函数while循环中)  由于没有数据 GetQueuedCompletionStatus()返回值为错误  调用一下函数关闭
::closesocket(pPerHandle->s);
::GlobalFree(pPerHandle);
::GlobalFree(pPerIO);

  2.10:(线程函数while循环中)  在此回到while循环 调用::GetQueuedCompletionStatus()函数  继续等待


// iocpTP.cpp : Defines the entry point for the console application.
//


#include "stdafx.h"


#include <stdio.h>
#include <windows.h>


// 初始化Winsock库
#include <winsock2.h>
#pragma comment(lib,"WS2_32.lib") // 






#define BUFFER_SIZE 1024


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;// 重叠结构
char buf[BUFFER_SIZE];// 数据缓冲区
int nOperationType;// 操作类型
#define OP_READ   1
#define OP_WRITE  2
#define OP_ACCEPT 3
} PER_IO_DATA, *PPER_IO_DATA;




DWORD WINAPI ServerThread(LPVOID lpParam)
{
// 得到完成端口对象句柄
HANDLE hCompletion = (HANDLE)lpParam;
printf("ServerThread Processor\n");
DWORD dwTrans;
PPER_HANDLE_DATA pPerHandle;
PPER_IO_DATA pPerIO;
while(TRUE)
{
// 在关联到此完成端口的所有套节字上等待I/O完成
printf("wait GetQueuedCompletionStatus  Done \n");
BOOL bOK = ::GetQueuedCompletionStatus(hCompletion, 
&dwTrans, (LPDWORD)&pPerHandle, (LPOVERLAPPED*)&pPerIO, WSA_INFINITE);
if(!bOK) // 在此套节字上有错误发生
{
printf("9\n");
::closesocket(pPerHandle->s);
::GlobalFree(pPerHandle);
::GlobalFree(pPerIO);
continue;
}

if(dwTrans == 0 &&// 套节字被对方关闭
(pPerIO->nOperationType == OP_READ || pPerIO->nOperationType == OP_WRITE))

{
printf("10\n");
::closesocket(pPerHandle->s);
::GlobalFree(pPerHandle);
::GlobalFree(pPerIO);
continue;
}
printf("11\n");
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;
printf("12\n");
::WSARecv(pPerHandle->s, &buf, 1, &dwTrans, &nFlags, &pPerIO->ol, NULL);

}
break;
case OP_WRITE: // 本例中没有投递这些类型的I/O请求
{
WSABUF buf;
buf.buf = pPerIO->buf ;
buf.len = BUFFER_SIZE;
pPerIO->nOperationType = OP_READ;
DWORD nFlags = 0;
::WSASend(pPerHandle->s, &buf, 1, &dwTrans, nFlags, &pPerIO->ol, NULL);
}
break;
case OP_ACCEPT:
{
}
break;
}
}
return 0;
}




void main()
{
// 初始化WS2_32.dll
BYTE minorVer = 0x02;
BYTE majorVer = 0x02;
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer, majorVer);
if(::WSAStartup(sockVersion, &wsaData) != 0)
{
}
int nPort = 5000;
// 创建完成端口对象,创建工作线程处理完成端口对象中事件
printf("Init NetWork\n");
HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
printf("CreateIoCompletionPort Done\n");
::CreateThread(NULL, 0, ServerThread, (LPVOID)hCompletion, 0, 0);
printf("Create Server Thread \n");
// 创建监听套节字,绑定到本地地址,开始监听
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_un.S_addr = INADDR_ANY;
::bind(sListen, (sockaddr*)&si, sizeof(si));
::listen(sListen, 5);


printf("Start Listen \n");
// 循环处理到来的连接
while(TRUE)
{
// 等待接受未决的连接请求
printf("Wait for Connect...\n");
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);
printf("Accept connect , assigned a CreateIoCompletionPort \n");
// 投递一个接收请求
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;
printf(" Mail a request!!! \n");
::WSARecv(pPerHandle->s, &buf, 1, &dwRecv, &dwFlags, &pPerIO->ol, NULL);
}


::WSACleanup();
}


测试程序:

//
// TCPClient.cppÎļþ
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")


int main()
{
BYTE minorVer = 0x02;
BYTE majorVer = 0x02;
//WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer, majorVer);
if(::WSAStartup(sockVersion, &wsaData) != 0)
{
exit(0);
}


// ´´½¨Ì×½Ú×Ö
SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(s == INVALID_SOCKET)
{
printf(" Failed socket() \n");
return 0;
}

// Ò²¿ÉÒÔÔÚÕâÀïµ÷ÓÃbindº¯Êý°ó¶¨Ò»¸ö±¾µØµØÖ·
// ·ñÔòϵͳ½«»á×Ô¶¯°²ÅÅ

// ÌîдԶ³ÌµØÖ·ÐÅÏ¢
sockaddr_in servAddr; 
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(5000);
// ×¢Ò⣬ÕâÀïÒªÌîд·þÎñÆ÷³ÌÐò£¨TCPServer³ÌÐò£©ËùÔÚ»úÆ÷µÄIPµØÖ·
// Èç¹ûÄãµÄ¼ÆËã»úûÓÐÁªÍø£¬Ö±½ÓʹÓÃ127.0.0.1¼´¿É
servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)
{
printf(" Failed connect() \n");
return 0;
}

// ·¢ËÍÊý¾Ý
send(s,"dddd",sizeof("dddd"),0);
// ½ÓÊÕÊý¾Ý
char buff[256];
int nRecv = ::recv(s, buff, 256, 0);
if(nRecv > 0)
{
buff[nRecv] = '\0';
printf(" ½ÓÊÕµ½Êý¾Ý£º%s", buff);
}

// ¹Ø±ÕÌ×½Ú×Ö
::closesocket(s);


::WSACleanup();
return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

见到的一篇IOCP流程 自己用demo实现了一下, 简单照抄,改动了一点点 的相关文章

随机推荐

  • 将hexo自定义域名升级https

    原文转载自我的博客https benym cn 前言 Tips 有什么问题可以在下方留言板留言哦 留下自己的邮箱 可以保证快速回复 最近在折腾博客 发现github上很多人说个人博客支持https很重要 原本的github io域名本来支持
  • 景联文科技可为多模态语音翻译模型提供数据采集支持

    8月22日Facebook的母公司Meta Platforms发布了一种能够翻译和转录数十种语言的人工智能模型 SeamlessM4T 可以在日常生活中或者商务交流中为用户提供更便捷的翻译和转录服务 相较于传统的文本翻译 这项技术的最大区别
  • 重启计算机一直转圈圈,Win10系统开机一直转圈圈进不了系统解决方法

    电脑越来越普及了 而大家都能熟练的操作电脑 但你知道如何解决Win10一直转圈圈不能进系统吗 不知道了吧 其实系统故障非常简单 大家只需要按照小编下述所说的方法操作就可以了 下面小编就给大家分享这篇Win10系统开机一直转圈圈进不了系统解决
  • deb 中标麒麟_注意:银河麒麟和中标麒麟不是同一个操作系统

    很多网友都想问 在国产操作系统中有两个叫麒麟的系统非常有名 一个是银河麒麟 另一个是中标麒麟 它们是否出自于同一个公司 是同一个操作系统 可以肯定的说 银河麒麟和中标麒麟不是同一个操作系统 这里请注意分辨了 包括和优麒麟也不同同一个操作系统
  • 智商100能看懂,内观,生男生女,集体潜意识及智人2.0

    一 这一轮人类发展趋势从外到内 要内观世界 1 人的身体前面是阴 背后是阳 但人是向前走路的 也就是从阳往阴走的 所以人类发展的趋势是阴 也就是往女性化走 从外到内 要内观世界 从目前人类的文明来说 现在的人类比古代的人类来说 男性越来越向
  • 最新高频Android笔试题分享,最新高频安卓面试题目分享

    前言 伟人曾经说过 书是人类进步的阶梯 书中自有黄金屋 书中自有颜如玉 读书破万卷 下笔如有神 书是唯一不死的东西 书籍是伟大的天才留给人类的遗产 最近有很多朋友在我的公众号上提问 Android开发的经典入门教材和学习路线 Android
  • 基于VLC实现RTSP推流桌面(共享桌面)

    基于VLC实现RTSP推流桌面 共享桌面 一 添加VLC头文件和库文件 二 封装RTSPServer推流类 三 测试代码 不清楚推流大概原理的小伙伴 参考 设置VLC播放器进行RTSP推流桌面 共享桌面 这里以VLC 2 2 6版本为例 因
  • 怎么将pdf文件转换成图片?三种方法

    在实际的工作过程中 PDF是非常常见的文档存储格式 也是很多网站默认的保存格式 对于PDF文件来说 其具备很多其他文件格式没有的优势和特点 例如 在PDF文件中 其排版整齐且固定 浏览直观且方便 为工作的开展提供了诸多便利 另外 为了能够提
  • [计算机网络]简单入门HTTPS : 确保Web网站安全

    前言 今天也是刚好看到HTTPS 感觉HTTPS有许多需要总结的地方 这里也是花点时间给大伙总结下 今天会从下面几个点入手给大伙介绍 HTTPS如何解决现有的HTTP安全问题 和HTTP的区别 HTTPS建立连接的过程 HTTPS的缺点 其
  • android蓝牙BLE(二) —— 通信

    android BLE系列 android蓝牙BLE 一 扫描 android蓝牙BLE 二 通信 android蓝牙BLE 三 广播 一 蓝牙基础协议 想了解蓝牙通信之前 需要先了解蓝牙两个最基本的协议 GAP 和 GATT 1 GAP
  • FreeCAD是什么、如何下载(windows+0.18.4版本)和安装以及中文设置

    目录 一 FreeCAD是什么 二 如何下载FreeCAD 三 FreeCAD安装过程 四 如何设置成中文 一 FreeCAD是什么 我本意是想用Qt连接CAD实现CAD的二次开发 实现在qt界面改变参数同时CAD图纸上的尺寸发生相应变化
  • Linux之Web服务器配置(Apache)

    摘要 Web Service技术 能使得运行在不同机器上的不同应用无须借助附加的 专门的第三方软件或硬件 就可相互交换数据或集成 依据Web Service规范实施的应用之间 无论它们所使用的语言 平台或内部协议是什么 都可以相互交换数据
  • 基于stm32f103c8t6HAL库六路电磁寻迹智能车

    基于stm32f103c8t6HAL库六路电磁寻迹智能车 学习单片机第一次参加相关比赛 下面分享一些关于调车的心得 1 控制舵机 舵机是控制小车转向的器件 而PWM波可以控制舵机 占空比越大 舵机旋转角度越大 接下来我们打开cubemx配置
  • FreeSwitch常用命令

    1 通话相关 先打客户 再转坐席 没有录音 EslMessage elme client sendSyncApiCommand originate sofia gateway huawei 015011275853 bridge user
  • JDBC数据源配置及管理

    JDBC驱动程序 JDBC驱动程序组件为java程序连接不同数据库系统提供服务 它通常由数据库系统方开发提供或由第三方提供 下载对应不同数据库的JDBC 数据库连接信息配置 URL 连接数据库系统资源描述符 DriverClass 数据库系
  • 交付文档注意事项

    最近涉及到项目交付 编写了很多技术文档 但因为没有经验导致多次修改 尤其是客户和我们技术人员的关注点其实是不一样的 就导致我没有抓住重点 导致反复修改 这里总结下我的一些经验 文档与技术协议合同对应 就我所经历的项目 前期的技术要求和最后的
  • 十大必掌握C++11新特性

    简介 C 11 之前被称作C 0x 即ISO IEC 14882 2011 是目前的C 编程语言的正式标准 它取代第二版标准ISO IEC 14882 2003 第一版ISO IEC 14882 1998发布于1998年 第二版于2003年
  • OCR测试——字体和背景颜色

    测试目的 测试图片中字体颜色和背景颜色对文字识别的影响 一 测试图片选择 黑色字体 白色背景 黑色字体 橙色背景 绿色字体 黑色背景 绿色字体 白色背景 白色字体 绿色背景 白色字体 橙色背景 橙色字体 白色背景 混合色字体 混合色背景 二
  • c# 遍历文件夹下的.exe文件,找到主应用程序文件

    遍历文件夹下的文件 exe文件 public static string ForeachFiles string FilePath SearchOption AllDirectories 指遍历全部的子文件夹 所有都遍历一次 string
  • 见到的一篇IOCP流程 自己用demo实现了一下, 简单照抄,改动了一点点

    要分析的实例分为两个线程 分别是主线程 MAIN 还有一个是创建的线程 ServerThread 1 主函数完成初始化工作 1 1 主线程 HANDLE hCompletion CreateIoCompletionPort INVALID