网络编程对象socke中的IOCP完成端口

2023-12-14 11:38

本文主要是介绍网络编程对象socke中的IOCP完成端口,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

为什么要采用Socket模型,而不直接使用Socket?

     原因源于recv()方法是堵塞式的,当多个客户端连接服务器时,其中一个socket的recv调用时,会产生堵塞,使其他链接不能继续。这样我们又想到用多线程来实现,每个socket链接使用一个线程,这样效率十分低下,根本不可能应对负荷较大的情况。于是便有了各种模型的解决方法,总之都是为了实现多个线程同时访问时不产生堵塞。

完成端口(IOCP)模型:

 

首先来说为什么要使用完成端口:原因还是因为为了解决recv方法为阻塞式的问题,WinSocket封装的WSARecv方法为非堵塞的方法。

          int WSARecv(

                      SOCKET s,

                      LPWSABUF lpBuffers,

                      DWORD dwBufferCount,

                      LPDWORD lpNumberOfBytesRecvd,

                      LPDWORD lpFlags,

                      LPWSAOVERLAPPED lpOverlapped,

                      LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine

                      );

     WSARecv为非阻塞的方法,其中第二个参数是I/O请求成功时,数据保存的地址。

     Socket的触发是属于网卡硬件的中断信号,只是此信号CPU不能直接获取状态,此时我们可以使之绑定Event事件,Event内核对象的状态时可以监听到的。这也就是WSAEventSelect模型的原理,当然重叠模型的最终原理也是如此。但Event的方法有着其弊病:当模型处理多线程事件时要调用WSAWaitForMultipleEvents函数,WSAWaitForMultipleEvents函数一次最多只能等待64个事件对象。所以当海量客户端连接服务器时,服务器将没有能力应对,于是我们使用完成端口。

    完成端口:

 

           HANDLE CreateIoCompletionPort(

                                               HANDLE FileHandle,             //要链接的Socket

                                               HANDLE ExistingCompletionPort,     //全局完成端口

     //同完成端口关联到一起的句柄,此处可为链接的socket,或是id等等(目地使接收到的socket知道是哪个socket)

                                               DWORD CompletionKey,             

                                               DWORD NumberOfConcurrentThreads

                 );

 

     此函数创建创建Socket与完成端口的链接,CreateIoCompletionPort函数被用于完成两个工作:

 

  • 用于创建—个完成端口对象。
  • 将一个句柄同完成端口关联到一起。

    用函数GetQueuedCompletionStatus等待全局完成端口的完成队列:

      BOOL     GetQueuedCompletionStatus(
                  HANDLE         CompletionPort,
                  LPDWORD      lpNumberOfBytes,
                 PULONG_PTR  lpCompletionKey, //此参数为CreateIoCompletionPort第三个参数传过来的句柄,通过此参数获得socket
                  LPOVERLAPPED* lpOverlapped,
                  DWORD         dwMilliseconds
                  );

   完成端口的工作原理是,把Socket和完成端口绑定,通过关联句柄传递传递参数,使得获取到的Socket能得知是那个socket,参数可以自定义可以是socket本身也可以是id等等。 

复制代码

#include "WinSock2.h"
#pragma comment(lib, "ws2_32.lib")#define MESSAGESIZE 1024SOCKET serverSocket;
DWORD WINAPI SocketProcAccept(LPVOID pParam);
DWORD WINAPI SocketProcMain(LPVOID pParam);enum SOCKETOPERATE
{soREVC
};struct SOCKETDATA
{WSAOVERLAPPED        overlapped;WSABUF                buf;char                sMessage[MESSAGESIZE];DWORD                dwBytes;DWORD                flag;SOCKETOPERATE        socketType;void Clear(SOCKETOPERATE type){ZeroMemory(this, sizeof(SOCKETDATA));buf.buf = sMessage;buf.len = MESSAGESIZE;socketType = type;}
};SOCKET CreateServiceSocket(int Port)
{int iError;WSAData data;iError = WSAStartup(0x0202, &data);SOCKET tmp = socket(AF_INET,SOCK_STREAM,0);if(tmp == INVALID_SOCKET){return INVALID_SOCKET;}SOCKADDR_IN addr;addr.sin_addr.s_addr = inet_addr("127.0.0.1");addr.sin_family = AF_INET;addr.sin_port = htons(Port);if((bind(tmp, (sockaddr*)&addr, sizeof(addr))) != 0){closesocket(tmp);return INVALID_SOCKET;}if((listen(tmp, INFINITE)) != 0){closesocket(tmp);return INVALID_SOCKET;}return tmp;
}int _tmain(int argc, _TCHAR* argv[])
{HANDLE CP = INVALID_HANDLE_VALUE;CP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);SYSTEM_INFO systemInfo;GetSystemInfo(&systemInfo);for (int i = 0; i<systemInfo.dwNumberOfProcessors; i++){CreateThread(NULL, NULL, &SocketProcMain, CP, NULL, NULL);}serverSocket = CreateServiceSocket(6565);if (serverSocket == INVALID_SOCKET){return 0;}CreateThread(NULL, NULL, &SocketProcAccept, CP, NULL, NULL);while(1){Sleep(10000);}CloseHandle(CP);closesocket(serverSocket);WSACleanup();return 0;
}DWORD WINAPI SocketProcAccept(LPVOID pParam)
{HANDLE CP = (HANDLE)pParam;SOCKADDR_IN addr;int len = sizeof(SOCKADDR_IN);SOCKET tmp;SOCKETDATA *lpSocketData;while(1){tmp = accept(serverSocket, (sockaddr*)&addr, &len);printf("Client Accept:%s\t:%d\n", inet_ntoa(addr.sin_addr), htons(addr.sin_port));CreateIoCompletionPort((HANDLE)tmp, CP, (DWORD)tmp, INFINITE);lpSocketData = (SOCKETDATA *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SOCKETDATA));lpSocketData->Clear(soREVC);WSARecv(tmp, &lpSocketData->buf, 1,&lpSocketData->dwBytes, &lpSocketData->flag, &lpSocketData->overlapped, NULL);}
}DWORD WINAPI SocketProcMain(LPVOID pParam)
{HANDLE CP = (HANDLE)pParam;SOCKADDR_IN addr;DWORD dwBytes;SOCKETDATA *lpSocketData;SOCKET clientSocket;while(1){GetQueuedCompletionStatus(CP, &dwBytes, (PULONG_PTR)&clientSocket, (LPOVERLAPPED*)&lpSocketData, INFINITE);if(dwBytes == 0xFFFFFFFF){return 0;}if(lpSocketData->socketType == soREVC){if(dwBytes == 0){closesocket(clientSocket);HeapFree(GetProcessHeap(), 0, lpSocketData);}else{lpSocketData->sMessage[dwBytes] = '\0';printf("%x\t:%s\n", (DWORD)clientSocket, lpSocketData->sMessage);lpSocketData->Clear(soREVC);WSARecv(clientSocket, &lpSocketData->buf, 1, &lpSocketData->dwBytes, &lpSocketData->flag, &lpSocketData->overlapped, NULL);}}}    
}

复制代码

 

这篇关于网络编程对象socke中的IOCP完成端口的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/492379

相关文章

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

SpringBoot使用OkHttp完成高效网络请求详解

《SpringBoot使用OkHttp完成高效网络请求详解》OkHttp是一个高效的HTTP客户端,支持同步和异步请求,且具备自动处理cookie、缓存和连接池等高级功能,下面我们来看看SpringB... 目录一、OkHttp 简介二、在 Spring Boot 中集成 OkHttp三、封装 OkHttp

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用

Python异步编程中asyncio.gather的并发控制详解

《Python异步编程中asyncio.gather的并发控制详解》在Python异步编程生态中,asyncio.gather是并发任务调度的核心工具,本文将通过实际场景和代码示例,展示如何结合信号量... 目录一、asyncio.gather的原始行为解析二、信号量控制法:给并发装上"节流阀"三、进阶控制

使用Python高效获取网络数据的操作指南

《使用Python高效获取网络数据的操作指南》网络爬虫是一种自动化程序,用于访问和提取网站上的数据,Python是进行网络爬虫开发的理想语言,拥有丰富的库和工具,使得编写和维护爬虫变得简单高效,本文将... 目录网络爬虫的基本概念常用库介绍安装库Requests和BeautifulSoup爬虫开发发送请求解

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3

Flask解决指定端口无法生效问题

《Flask解决指定端口无法生效问题》文章讲述了在使用PyCharm开发Flask应用时,启动地址与手动指定的IP端口不一致的问题,通过修改PyCharm的运行配置,将Flask项目的运行模式从Fla... 目录android问题重现解决方案问题重现手动指定的IP端口是app.run(host='0.0.