c++使用完成端口实现服务器的高性能并发

article/2025/9/26 19:03:06

如何使用c++,借助完成端口完成大并发服务器的搭建,是今天要讨论的问题,套路如下:


套路总结一下:
创建完成端口
依据CPU核数创建一定数量的线程
线程中不断调用GetQueuedCompletionStatus检查完成端口状态,分别给予处理
创建一个socket,绑定IP和端口
将这个socket绑定到第一步创建的完成端口上




这里写图片描述


获取当前服务器的CPU核数,根据核数创建一定数量的线程



这里写图片描述



这里写图片描述




这里写图片描述


GetQueuedCompletionStatus这个函数非常重要,上面创建的线程不断检查完成端口的状态,有则处理


void CIocpCtrl::OnExecute()
{SPerHandleData* pstPerHandleData;SPerIoData*     pstPerIoData;CCPSock*        poSock;CCpListener*    poListener;BOOL            bRet;DWORD           dwByteTrabsferred;//通过while(true)循环,不断的检查while(true) {pstPerHandleData    = NULL;pstPerIoData        = NULL;dwByteTrabsferred   = 0;//最重要的就是GetQueuedCompletionStatus这个函数bRet = GetQueuedCompletionStatus(m_hCompletionPort,&dwByteTrabsferred,(PULONG_PTR)&pstPerHandleData,(LPOVERLAPPED*)&pstPerIoData,INFINITE);// 检查是否是线程退出if(NULL == pstPerHandleData){return;}if(pstPerHandleData->bListen){// for listen eventpoListener = (CCpListener*)pstPerHandleData->ptr; //注意这里if(NULL != poListener &&  NULL != pstPerIoData){poListener->OnAccept(bRet, pstPerIoData); //接收一个新连接}else {SDASSERT(false);}}else {//for non-listen event poSock = (CCPSock*)pstPerHandleData->ptr; //注意这里if ( NULL == poSock ){continue;}if( FALSE == bRet || NULL == pstPerIoData ){               if (::WSAGetLastError()!=ERROR_IO_PENDING){INFO(_SDT("[%s:%d]CCPSock connID=%d error %d, close it"), MSG_MARK, poSock->GetConnectionID(), ::WSAGetLastError());poSock->OnClose();}               }else{       //判断类型switch(pstPerIoData->nOp){case IOCP_RECV:{poSock->DecPostRecv();if (dwByteTrabsferred > 0){poSock->OnRecv(dwByteTrabsferred); //处理接收到的数据}else{INFO(_SDT("[%s:%d]CCPSock connID=%d error %d, close it, socket :%d "), MSG_MARK, poSock->GetConnectionID(), ::WSAGetLastError(), poSock->GetSock());poSock->OnClose();}}break;case IOCP_SEND:{poSock->DecPostSend();if (dwByteTrabsferred > 0){poSock->OnSend(dwByteTrabsferred); //处理发送的数据}else{INFO(_SDT("[%s:%d]CCPSock connID=%d error %d, close it"), MSG_MARK, poSock->GetConnectionID(), ::WSAGetLastError());poSock->OnClose();}}break;case IOCP_CLOSE:{poSock->OnClose(false); //关闭连接}break;default:;}}}}
}

//提供一个入口,供其它socket绑定完成端口
bool CIocpCtrl::AssociateWithIocp(SOCKET hSock, SPerHandleData* pstData)
{if (NULL == m_hCompletionPort){return false;}if(NULL == CreateIoCompletionPort((HANDLE)hSock, m_hCompletionPort, (ULONG_PTR)pstData, 0)){WARN(_SDT("CIocpCtrl::AssociateWithIocp, failed, errno %d"), WSAGetLastError());return false;}return true;
}

下面就是一个接收处理:

void CCpListener::OnAccept(BOOL bSucc, SPerIoData* pstPerIoData)
{SOCKET hSock = pstPerIoData->hSock; //取出socketif(false == m_bStart){InterlockedIncrement((volatile LONG*)&m_dwReleaseCount);closesocket(hSock);return;}this->PostAcceptEx(pstPerIoData); //接收一个连接之后,就要顺道再投递一个AcceptEx if(FALSE == bSucc){WARN(_SDT("CCpListener::OnAccept, accept failed, errno %d"), ::WSAGetLastError());closesocket(hSock);}else{//下面就是封装这个连接,以及在这个新连接上投递接收请求CConnData* pConnData = CConnDataMgr::Instance()->Alloc(m_dwRecvBufSize, m_dwSendBufSize);CCPSock * poSock = &pConnData->sock;        CUCConnection* poConnection = & pConnData->connection;//+lcjif (0 != ::setsockopt(hSock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&m_hListenSock, sizeof(SOCKET))){WARN(_SDT("setsockopt for new socket on UpdateConetext failed, errno=%d"), ::WSAGetLastError());}if (g_bNodelay){const CHAR szOpt = 1;if (0 != ::setsockopt(hSock, IPPROTO_TCP, TCP_NODELAY, (char *)&szOpt, sizeof(char))){WARN(_SDT("setsockopt for new socket on UpdateConetext failed, errno=%d"), ::WSAGetLastError());}}poSock->SetSock(hSock);poSock->SetPacketParser(m_poPacketParser);poConnection->SetAccept(true);poConnection->SetParentID(0);sockaddr_in RemoteAddr, LocalAddr;GetSockAddress(pstPerIoData, RemoteAddr, LocalAddr);poConnection->SetLocalIP(LocalAddr.sin_addr.s_addr);poConnection->SetLocalPort(SDNtohs(LocalAddr.sin_port));poConnection->SetRemoteIP(RemoteAddr.sin_addr.s_addr);poConnection->SetRemotePort(SDNtohs(RemoteAddr.sin_port));//注意这里,session和Connection连接起来ISDSession* poSession = m_poSessionFactory->CreateSession(poConnection);if(NULL == poSession){DBG(_SDT("CCpListener::OnAccept, CreateSession failed"));closesocket(hSock);CConnDataMgr::Instance()->Release(pConnData);return;}poConnection->SetSession(poSession);poSock->SetConnect(TRUE);
#ifndef SDENT_HAS_RECV_QUEUEpoConnection->OnAssociate();
#endifif(false == poSock->AssociateWithIocp()) //将新接收的socket绑定完成端口{poSock->DoClose();}else{if(false == poSock->PostRecv()) //投递一个接收请求{poSock->DoClose();}}}




FR:海涛高软(hunk Xu)


http://chatgpt.dhexx.cn/article/mFdAKVQO.shtml

相关文章

C#高性能大容量SOCKET并发完成端口例子(有C#客户端)完整实例源码

遥望星空 好好干,有前途! 博客园首页新随笔联系管理订阅 随笔- 1082 文章- 0 评论- 151 C#高性能大容量SOCKET并发(转) C#高性能大容量SOCKET并发(零):代码结构说明 C#高性能大容量SOCKET并发(一…

完成端口学习笔记(一):完成端口+控制台 实现文件拷贝

最近在整理手里一个项目的后台服务端归档程序,重新梳理了一下有关“完成端口”的知识,发现还是有很多模棱两可的地方,下面记录一下再次学习的点滴,该篇博文还会有后续的补充章节,不知道什么时间会再补充^_^。 IO概念 还…

Socket编程模型之完成端口模型

转载请注明来源:http://blog.csdn.net/caoshiying?viewmodecontents 一、回顾重叠IO模型 用完成例程来实现重叠I/O比用事件通知简单得多。在这个模型中,主线程只用不停的接受连接即可;辅助线程判断有没有新的客户端连接被建立,如…

完成端口(IOCP)详解[2/2](转载)

版权声明:本文为CSDN博主「PiggyXP」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/piggyxp/article/details/6922277 五 使用完成端口的基本流程 说了这么多的废话&a…

Windows io完成端口

Windows 提供一种称为I/O完成端口(I/O Completion Port)机制,能够让I/O的完成处理交由一个专门的线程池来完成,而线程池的线程数量是一个可配置的参数。这种做法将I/O请求的发起动作与完成处理分离到了不同的线程中。 I/O完成端口是内核对象。个人的感觉…

完成端口(Completion Port)详解

http://blog.csdn.net/piggyxp/article/details/6922277 手把手叫你玩转网络编程系列之三 完成端口(Completion Port)详解 ----- By PiggyXP(小猪) 前 言 本系列里完成端口的代码在两年前就已经写好了,但是由于许久没有写东西了,不知该如何提笔&#xf…

完成端口(CompletionPort)详解 - 手把手教你玩转网络编程系列之三

手把手叫你玩转网络编程系列之三 完成端口(Completion Port)详解 ----- By PiggyXP(小猪) 前 言 本系列里完成端口的代码在两年前就已经写好了,但是由于许久没有写东西了,不知该如何提笔,所以这篇文档总是在酝酿之中……酝酿了两年之后&…

树同构-树哈希

树同构-树哈希 题目描述 题解 对于无根树,由于数据范围较小,可以直接以每个点为根dfs一次,维护其树哈希的值,然后用并查集维护 (若数据范围大一些,可以以树的重心跑dfs) 代码实现 #include&…

2.3 树的同构(树,c)

树的同构 树的同构输入格式:输出格式:输入样例1(对应图1):输出样例1:输入样例2(对应图2):输出样例2: 题意理解输入两棵二叉树的信息,判断是否同构(对应图1) 求解思路二叉…

03-树1 树的同构

题目 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。 图1 图2 现给…

『树同构的判定(树Hash)』CF718D:Andrew and Chemistry

题目描述 题解 这道题目的难点在于如何判断树的同构,这就是所谓的树的哈希。 我们假设需要求解以x为根的子树的hash值,我们可以将子树的hash值存储到vector内,排序以后用map来判断重复。这个写法十分简单。具体如下: int dfs(i…

数据结构之树的同构

目录 前言 题意理解 求解思路 二叉树表示 程序框架搭建 读数据建二叉树 二叉树同构判别 前言 本篇主要讲有关二叉树的同构判断。 题意理解 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则称这两棵树是“同构”的。 例如: 左图…

2020牛客多校10:Identical Trees(树hash + 树同构 + 费用流模板)

题意:给出两棵同构的有根树,同构修改点的标号使得两棵树完全一样,至少需要修改多少次。 分析:肯定是将子树和另外一棵的某个子树对应,而两棵子树的问题是一个子问题,显然只有同构的子树才可以对应&#xf…

哈希算法在判定树同构方面的应用(下)

哈希算法在判定树同构方面的应用 在上一篇文章中我们介绍了 枚举根节点哈希 和 求重心哈希 两种方法来判断两棵无根树是否同构。 但是如果有些题目中我必须要计算出每个根节点的 f f f 值,且 n ≤ 1 e 5 n\le 1e5 n≤1e5,我们要怎么办呢?…

树的同构判断

使用递归的思路解决树的同构的判断 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2…

树同构的判断

结构中的flag用来标记该元素是否被访问过&#xff0c;judge函数中的flag为了使一行的四个元素即使又被访问过的元素也要读完一整行。 #include<stdio.h> #include<stdbool.h> #include<stdlib.h> typedef struct TreeNode *Tree; struct TreeNode{int v;Tre…

哈希算法在判定树同构方面的应用(上)

哈希算法在判定树同构方面的应用&#xff08;上&#xff09; &#xff08;一&#xff09;需要掌握的前置知识&#xff1a; &#xff08;1&#xff09;素数筛法&#xff1a;埃氏筛或者欧拉筛均可以。 以下为欧拉筛&#xff1a; const int maxn100100; int p[maxn],cnt0; bool…

树同构判定算法

树同构判定 树同构判定 图同构与树同构 同的同构问题还没有有效算法。 树的同构本质上寻找不同树之间的双射关系。 通过对树编码&#xff0c;将树的同构问题转化为编码比较问题。 有根树的同构严格强于图同构关系。 如上&#xff0c;图同构的两张图转化成树&#xff0c;…

数据结构(三)—— 树(4):树的同构

数据结构系列内容的学习目录 → \rightarrow →浙大版数据结构学习系列内容汇总。 题意理解&#xff1a; 给定两棵树T1和T2。如果T1可以通过若干次左右子结点互换就变成T2&#xff0c;则我们称两棵树是“同构”的。         现给定两棵树&#xff0c;如下图所示&#xf…

【树】树的同构

【树】 树的同构 题目要求&#xff1a; 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2&#xff0c;则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的&#xff0c;因为我们把其中一棵树的结点A、B、G的左右孩子互换后&#xff0c;就得到另外一棵树。而…