网络编程对象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

相关文章

Debian 13升级后网络转发等功能异常怎么办? 并非错误而是管理机制变更

《Debian13升级后网络转发等功能异常怎么办?并非错误而是管理机制变更》很多朋友反馈,更新到Debian13后网络转发等功能异常,这并非BUG而是Debian13Trixie调整... 日前 Debian 13 Trixie 发布后已经有众多网友升级到新版本,只不过升级后发现某些功能存在异常,例如网络转

Nginx中配置使用非默认80端口进行服务的完整指南

《Nginx中配置使用非默认80端口进行服务的完整指南》在实际生产环境中,我们经常需要将Nginx配置在其他端口上运行,本文将详细介绍如何在Nginx中配置使用非默认端口进行服务,希望对大家有所帮助... 目录一、为什么需要使用非默认端口二、配置Nginx使用非默认端口的基本方法2.1 修改listen指令

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

AOP编程的基本概念与idea编辑器的配合体验过程

《AOP编程的基本概念与idea编辑器的配合体验过程》文章简要介绍了AOP基础概念,包括Before/Around通知、PointCut切入点、Advice通知体、JoinPoint连接点等,说明它们... 目录BeforeAroundAdvise — 通知PointCut — 切入点Acpect — 切面

Python开发简易网络服务器的示例详解(新手入门)

《Python开发简易网络服务器的示例详解(新手入门)》网络服务器是互联网基础设施的核心组件,它本质上是一个持续运行的程序,负责监听特定端口,本文将使用Python开发一个简单的网络服务器,感兴趣的小... 目录网络服务器基础概念python内置服务器模块1. HTTP服务器模块2. Socket服务器模块

C#异步编程ConfigureAwait的使用小结

《C#异步编程ConfigureAwait的使用小结》本文介绍了异步编程在GUI和服务器端应用的优势,详细的介绍了async和await的关键作用,通过实例解析了在UI线程正确使用await.Conf... 异步编程是并发的一种形式,它有两大好处:对于面向终端用户的GUI程序,提高了响应能力对于服务器端应

Go语言网络故障诊断与调试技巧

《Go语言网络故障诊断与调试技巧》在分布式系统和微服务架构的浪潮中,网络编程成为系统性能和可靠性的核心支柱,从高并发的API服务到实时通信应用,网络的稳定性直接影响用户体验,本文面向熟悉Go基本语法和... 目录1. 引言2. Go 语言网络编程的优势与特色2.1 简洁高效的标准库2.2 强大的并发模型2.

javaSE类和对象进阶用法举例详解

《javaSE类和对象进阶用法举例详解》JavaSE的面向对象编程是软件开发中的基石,它通过类和对象的概念,实现了代码的模块化、可复用性和灵活性,:本文主要介绍javaSE类和对象进阶用法的相关资... 目录前言一、封装1.访问限定符2.包2.1包的概念2.2导入包2.3自定义包2.4常见的包二、stati