提高IOCP 效率的一些方法,技巧 (来自WINDOWS 网络编程第二版)

用完成端口开发大响应规模的Winsock应用程序(4) 接受连接请求服务器要做的最普通的事情之一就是接受来自客户端的连接请求。在套接字上使用重叠I/O接受连接的惟一API就是AcceptEx()函数。有趣的是,通常的同步接受函数accept()的返回值是一个新的套接字,而AcceptEx()函数则需要另外一个套接字作为它的参数之一。这是因为AcceptEx()是一个重叠操作,所以你需要事先创建一个套接字(但不要绑定或连接它),并把这个套接字通过参数 阅读详情

 

 

1. AcceptEx:

BOOL
PASCAL FAR
AcceptEx (
   IN SOCKET sListenSocket,
   IN SOCKET sAcceptSocket,
   IN PVOID lpOutputBuffer,
   IN DWORD dwReceiveDataLength,
   IN DWORD dwLocalAddressLength,
   IN DWORD dwRemoteAddressLength,
   OUT LPDWORD lpdwBytesReceived,
   IN LPOVERLAPPED lpOverlapped
   );

    用来发起一个异步的调用, 接受客户端将要发出的连接请求. 与 accept 不同的是, 你必须先手动创建一个 socket 提供给 AcceptEx, 用来接受连接 ( accept 是内在地创建一个 socket 接受连接, 并返回值 ). 而且, accept 创建的 socket 会自动继承监听 socket 的属性, AcceptEx 却不会. 因此如果有必要, 在 AcceptEx 成功接受了一个连接之后, 我们必须调用:

    setsockopt( hAcceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,  ( char* )&( hListenSocket ), sizeof( hListenSocket ) );

来做到这一点.


    AcceptEx 允许在接受连接的同时接收对方发来的第一组数据, 这当然是出于性能的考虑. 但是这时候 AcceptEx 最少要接收到一个字节的数据才会返回, 一旦碰到恶意连接它就永远不会返回了. 关闭这项功能的方式是: 把参数 dwReceiveDataLength 至为 0, 打开则相反. 当然了, 如果一定要启用这个功能, 我们也有防御的办法. 启动一个线程定时地检测每一个 AcceptEx 是否已经连接, 连接时间为多久, 以此判断对方是否是恐怖分子:

    int iSecs;
    int iBytes = sizeof( int );
    getsockopt( hAcceptSocket, SOL_SOCKET, SO_CONNECT_TIME, (char *)&iSecs, &iBytes );

iSecs 为 -1 表示还未建立连接, 否则就是已经连接的时间.


    调用 AcceptEx 的方式:

    #include <Mswsock.h>  // for WSAID_ACCEPTEX
    typedef BOOL ( WINAPI * PFNACCEPTEX ) ( SOCKET, SOCKET, PVOID, DWORD, DWORD, DWORD, LPDWORD, LPOVERLAPPED );
    PFNACCEPTEX pfnAcceptEx;
    DWORD dwBytes;
    GUID guidAcceptEx = WSAID_ACCEPTEX;
    ::WSAIoctl( hListenSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx, sizeof( guidAcceptEx ), &pfnAcceptEx, sizeof( pfnAcceptEx ), &dwBytes, NULL, NULL );

    DWORD uAddrSize = sizeof( SOCKADDR_IN ) + 16;
    DWORD uDataSize = 0;
    BOOL bRes = pfnAcceptEx( hListenSocket, hAcceptSocket, buffer, uDataSize, uAddrSize, uAddrSize, &uAddrSize, ( LPWSAOVERLAPPED )overlapped );

    其中, buffer 和 overlapped 要根据你自己的用途来定了, 这里只是拿来充数.

    一旦 AcceptEx 调用完成 ( 通过完成端口通知你 ), 接下来的步骤就是 1. 上面讲的 SO_UPDATE_ACCEPT_CONTEXT;

2. 将 hAcceptSocket 绑定到完成端口.

 



2. TransmitFile

   TransmitFile 顾名思义是用来进行文件传输的函数, 全自动无需干涉的. 在 Win NT 专业版/家庭版上无法发挥全部性能. 在这里只讨论它的一个功能: 关闭一个 SOCKET 并再次初始化它. 创建一个 SOCKET 是很耗时的, 因此这么做可以节约大量时间:

    #include <Mswsock.h>  // for WSAID_TRANSMITFILE
    typedef BOOL ( WINAPI * PFNTRANSMITFILE ) ( SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD );
    PFNACCEPTEX pfnTransmitFile;
    DWORD dwBytes;
    GUID guidTransmitFile = WSAID_TRANSMITFILE;
    ::WSAIoctl( hListenSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidTransmitFile,
sizeof( guidTransmitFile ), &pfnTransmitFile,
sizeof( pfnTransmitFile ), &dwBytes, NULL, NULL );

    pfnTransmitFile( hAcceptSocket, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | TF_REUSE_SOCKET );

    经过这个函数处理的 SOCKET 可以作为接受连接的 socket 提交给 AcceptEx 再次使用. 当这样的 socket 接受连接成功后, 如果往完成端口上绑定会出错 - 因为上次接受连接成功时已经绑定过了, 这个错误可以忽略.

 



3. FD_ACCEPT

    即使我们在程序启动时发起了再多的 AcceptEx , 也有可能碰到数目不够用户连不上来的情况. 在 Win2000 或更高版本的系统上, 我们可以通过 WSAEventSelect 注册一个 FD_ACCEPT 事件. 当 AcceptEx 数目不足以应付大量的连接请求时, 这个事件会被触发. 于是我们就可以发出更多的 AcceptEx, 而且我们还可以抽空辨别一下 AcceptEx 为什么这么快就用光了, 是不是碰上攻击者了( 辨别方法见上文所述 ) ?

    HANDLE hAcceptExThreadEvent = ::CreateEvent( NULL, TRUE, FALSE, _T("AcceptExThreadEvent") );
    ::WSAEventSelect( hListenSocket, hAcceptExThreadEvent, FD_ACCEPT );

    DWORD WINAPI AcceptExThread( LPVOID lpParameter )
    {
 // 负责保证有足够多的 AcceptEx 可以接受连接请求的线程

        for( UINT i = 0; i < 10; i ++ ) // 程序启动时发起的 AcceptEx
        {  
            pfnAcceptEx( hListenSocket, ... );
        }

        while( TRUE )
        {
            DWORD dwRes = ::WaitForSingleObject( hAcceptExThreadEvent, INFINITE );
     if( dwRes == WAIT_FAILED )
     {
         break;
     }
     ::ResetEvent( hAcceptExThreadEvent );
     if( m_sbWaitForExit )
     {   // 当然, 退出线程也是这个 Event 通知
         break;
     }
     pfnAcceptEx( hListenSocket, ... );

            //
            // ... 在此检查是否被攻击
            //
        }
        return 0;
    }
 
    要说明的是, WSAEventSelect() 所需的 WSAEVENT 和 CreateEvent() 所创建的 EVENT 是通用的.

 



4. WSASend 和 WSARecv

    默认情况下, 每一个 socket 在系统底层都拥有一个发送和接收缓冲区.

    我们发送数据时, 实际上是把数据复制到发送缓冲区中, 然后 WSASend 返回. 但是如果发送缓冲区已经满了, 那么我们在 WSASend 中指定的缓冲区就会被锁定到系统的非分页内存池中, WSASend 返回 WSA_IO_PENDING. 一旦网络空闲下来, 数据将会从我们提交的缓冲区中直接被发送出去, 与 " 我们的缓冲区->发送缓冲区->网络 " 相比节省了一次复制操作.

    WSARecv 也是一样, 接收数据时直接把接收缓冲区中的数据复制出来. 如果接收缓冲区中没有数据, 我们在 WSARecv 中指定的缓冲区就会被锁定到系统的非分页内存池以等待数据, WSARecv 返回 WSA_IO_PENDING. 如果网络上有数据来了, 这些数据将会被直接保存到我们提供的缓冲区中.
  
   如果一个服务器同时连接了许多客户端, 对每个客户端又调用了许多 WSARecv, 那么大量的内存将会被锁定到非分页内存池. 锁定这些内存时是按照页面边界来锁定的, 也就是说即使你 WSARecv 的缓存大小是 1 字节, 被锁定的内存也将会是 4k. 非分页内存池是由整个系统共用的, 如果用完的话最坏的情况就是系统崩溃. 一个解决办法是, 使用大小为 0 的缓冲区调用 WSARecv. 等到调用成功时再换用非阻塞的 recv 接收到来的数据, 直到它返回 WSAEWOULDBLOCK 表明数据已经全部读完. 在这个过程中没有任何内存需要被锁定, 但坏处是效率稍低.

 
异步通信之IOCP详解 一、 概述 学习完网络基础,在写C/S应用程序时,大多童靴写服务器基本都没有用到io模型,基本都是采用“accept同步拥塞通讯和多线程方式”与客户端通讯。但当有成千上万客户端请求连接并与服务器通讯时,多线程的创建与CPU上下文的切换,服务器端压力可想而知,在资源有限的情况在,选择一个好的io模型才能搭建高性能服务器。其中IOCP广泛运用于个高性能服务器程序,apache服务器就是IOCP实现。 同步通讯和异步通信 在写网络程序时,我们知道CPU运行速度非常快,而在与IO设备进行数据交换时速度简直不忍直视。 阅读详情

相关推荐

完成端口与AcceptEx

关于IOCP网上到处都是资料,说的也很详细。我在这里就不再多说了,这只是本人在学习IOCP时的笔记,和配合AcceptEx写的一个极小的服务端程序。由于刚刚接触ICOP加上本人刚毕业不到一年,所以里面的理解或观点可能有误,还请大家多多批评!          VC6.0开发,旨在体现IOCP的架构,忽略细节,服务程序的功能只是接收客户连接,接着接收到客户数据,然后原封不动的返回给客户!  

u010025913的专栏 1万+

编写完成端口网络服务器的一些说明 (1)

 1. AcceptEx: BOOLPASCAL FARAcceptEx (   IN SOCKET sListenSocket,   IN SOCKET sAcceptSocket,   IN PVOID lpOutputBuffer,   IN DWORD dwReceiveDataLength,   IN DWORD dwLocalAddressLength,   IN DWORD

sun201201的专栏 802

高性能Windows网络编程:蓝色枫叶IOCP库实战指南

在现代的IT行业和相关领域中,异步I/O(Asynchronous I/O,简称AIO)已经成为构建高性能系统的关键技术之一。IOCP(Input/Output Completion Ports)技术,作为实现Windows平台异步I/O操作的一种机制,为开发者提供了一种高效的I/O处理方式。它允许应用程序在等待磁盘、网络等I/O操作完成的同时,继续执行其他任务,极大地提升了系统资源的利用率和应用性能。

weixin_42590539的博客 859

AcceptEx与完成端口(IOCP)结合实例

前言 在windows平台下实现高性能网络服务器,iocp(完成端口)是唯一选择。编写网络服务器面临的问题有:1 快速接收客户端的连接。2 快速收发数据。3 快速处理数据。本文主要解决第一个问题。 AcceptEx函数定义 BOOL AcceptEx( SOCKET sListenSocket, SOCKET sAcceptSocket, PVOI...

weixin_34294649的博客 475

Windows网络编程实战指南:从Winsock到IOCP的核心框架与排查技巧

网络通信是现代软件开发的基石,而Socket编程则是最基础的数据交换方式。在Windows平台上,Winsock API 作为TCP/IP协议栈的接口,提供了从阻塞模式到异步模型的多种实现路径。面对不同并发规模,开发者需要选择合适的模型:低并发可使用阻塞Socket加多线程,高并发场景则需借助IOCP完成端口实现内核级异步IO,从而大幅提升系统吞吐量。这些技术广泛应用于即时通讯、远程控制、局域网工具等场景,同时伴随而来的粘包拆包、连接重置等错误排查也是工程实践中的常见挑战。理解这些核心原理,将帮助开发者规避

weixin_32667955的博客 309

将Windows IOCP集成至libevent提升性能

libevent是一个高性能、轻量级的事件驱动网络库,被广泛应用于需要高效网络处理的场景。它支持多种操作系统,并提供了丰富的网络事件处理接口。兼容性保持与平台检测在跨平台编程中是一个重要的环节,它要求开发者深入了解各个平台的特性和差异,并采取相应的策略来确保代码的一致性和稳定性。通过条件编译、平台自适应的代码检测机制、版本控制、兼容性测试以及快速修复流程等手段,开发者能够有效地解决跨平台编程所面临的兼容性挑战。

weixin_42443533的博客 894

windows网络编程(第二版)_windows网络编程iocp模型

IOCP模型与网络编程一、前言:1. 我想只要是写过或者想要写C/S模式网络服务器端的朋友,都应该或多或少的听过完成端口的大名吧,完成端口会充分利用Windows内核来进行I/O的调度,是用于C/S通信模式中性能最好的网络通信模型,没有之一;甚至连和它性能接近的通信模型都没有。2. 完成端口和其他网络通信方式最大的区别在哪里呢?(1) 首先,如果使用“同步”的方式来通信的话,这里说的同步的方式就是...

weixin_36087357的博客 652

Windows高性能IOCP实现源码深度解析

通常情况下,中保存的是用户自定义的上下文指针,而overlapped指向的是之前提交的OVERLAPPED结构,可以通过结构体偏移量提取封装的上下文。示例代码:逐行解释:使用offsetof宏计算OVERLAPPED在结构体中的偏移。通过指针运算还原整个IO_CONTEXT结构。提取用户上下文指针,用于后续业务处理。

weixin_35509395的博客 1173

windows网络编程_windows网络编程iocp模型

IOCP模型与网络编程一、前言:1. 我想只要是写过或者想要写C/S模式网络服务器端的朋友,都应该或多或少的听过完成端口的大名吧,完成端口会充分利用Windows内核来进行I/O的调度,是用于C/S通信模式中性能最好的网络通信模型,没有之一;甚至连和它性能接近的通信模型都没有。2. 完成端口和其他网络通信方式最大的区别在哪里呢?(1) 首先,如果使用“同步”的方式来通信的话,这里说的同步的方式就是...

weixin_39654917的博客 280

构建高性能UDP服务器:完成端口IOCP+UDP源码实战

用户数据报协议(UDP)是一种简单的无连接协议,为网络应用提供了一种无需建立连接就能发送数据的方式。与传输控制协议(TCP)相比,UDP具有以下特点:无连接:UDP发送数据前不需要建立连接,减少了延迟。尽最大努力交付:UDP不会对数据进行排序或者确认,如果数据丢失或重复也不会进行重传。轻量级:由于省去了建立连接和重传机制的开销,UDP头部只有8字节,比TCP的20字节头部要小。不可靠。

weixin_35636570的博客 910

FastGPT 引申:借鉴 FastGPT 基于MySQL + ES 实现知识库(含表结构以及核心代码)

FastGPT 引申:借鉴 FastGPT 基于MySQL + ES 实现知识库(含表结构以及核心代码)

蜗牛的专栏 3435

Linux 的 epoll 与 Windows 的 IOCP 详解

简单说,就是你手里有很多任务(比如很多客户端的请求),但系统的核心(线程或者进程)资源有限,你怎么快速、同时处理这些请求?这个问题就属于“多路复用”范畴。就像你在吃饭,有很多盘菜(请求)摆在桌子上,你想用一只筷子(单个线程)快速夹起来吃掉,并且处理所有盘子里的菜。如果每个请求都用单独的线程跑,效率低,资源浪费严重。而“多路复用”技术,就是让一只或者少数几只“筷子”可以轮流“夹”住多个“盘子”,高效处理。epoll:Linux中高效的多路复用事件通知机制,支持大规模连接,节省资源。IOCP。

2301_80355452的博客 1408

Modbus4J vs EasyModbus4J:哪个Java库更适合你的工业项目?

本文深入对比了Java领域两大Modbus通信库Modbus4J与EasyModbus4J。Modbus4J设计稳健、类型安全,适合复杂业务集成;EasyModbus4J基于Netty,在高并发场景下性能更优。文章从架构、性能、API及生产环境多维度分析,为工业物联网项目选型提供决策依据。

weixin_28475533的博客 310

iocp的一些有用资料

IOCP中的AcceptEx WSAEventSelect 提高IOCP 效率的一些方法,技巧 (来自WINDOWS 网络编程第二版) (这里的一些方法,王艳平的网络编程也提到过) 用完成端口开发大响应规模的Winsock应用程序

bsnry的专栏 622

永磁同步电机ADRC控制策略优化:从理论到Simulink仿真实践

本文深入探讨了永磁同步电机自抗扰控制(ADRC)策略的优化与实践。针对传统PID在动态响应、抗扰及噪声抑制方面的不足,详细解析了ADRC三大核心组件——跟踪微分器(TD)、扩张状态观测器(ESO)与非线性状态误差反馈(NLSEF)的工作原理。通过手把手的Simulink仿真教程,展示了从算法编写、模型搭建到参数整定的完整流程,并进阶实现了位置-速度双环ADRC协同控制,为高性能电机伺服系统设计提供了从理论到实践的清晰指南。

root9的博客 412

OS实验xv6 6.S081 开坑

OS实验xv6 6.S081 开坑 终于把xv6 2019 6.S081做完了,网络部分没有写,因为有计网实验了。怎么说呢,xv6的坑有点多,能做完多亏了:和我同学ljj交流,参考RedemptionC老哥的博客(他写的非常详细,遗憾的是,他好像没有写mmap),再者就是参考这位老哥的做法(没有源码,写得不是特别详细,不过有借鉴作用,mmap就是借鉴了他的思想)……废话不多说了,直接开始。 实验指导 首推RedemptionC的博客 这位老哥的个人博客 xv6 6.S081官网(后面的实验都要参考官网

不定期更新系统使用、编程小技巧,哔哩哔哩账号:https://space.bilibili.com/399455629,欢迎关注 4493

IOCP完成端口通俗讲义与项目实战

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

jaye8090的博客 2936

【时空图神经网络 & 交通】相关模型3:STFGNN | 空间-时间依赖性 | 基于数据驱动的方法来生成“时间图” | 时空融合图模块,门控卷积模块 | 动态时间规整 | 顶会文章解析

STFGNN(时空融合图神经网络)在交通流量预测中的优势主要体现在以下几个方面:首先,它提出了一种数据驱动的方法生成“时间图”,弥补了传统空间图可能无法反映的某些相关性。其次,STFGNN通过并行处理不同时间段的空间图和时间图,有效地学习隐藏的时空依赖关系。此外,它将融合图模块与门控卷积模块整合到一个统一层中,通过层层堆叠处理长序列,进一步增强了模型的表达能力。实验结果表明,STFGNN在多个交通数据集上表现出色,优于其他基准方法,展示了其在实际应用中的强大潜力。

追光者♂:记录、分享、总结、提升,现象级专栏《Python从入门到人工智能》作者,无惧黑暗,坚信曙光 384

Netty - 五种 I/O 多路复用机制 select、poll、epoll、kqueue、iocp(windows) 对比

综上所述,select 和 poll 在大规模连接场景下性能较差,而 epoll 和 kqueue 则具有更好的性能和扩展性,其中 epoll 更适用于 Linux 平台,而 kqueue 则适用于 BSD 系统。而对于 Windows 平台,IOCP 是首选的高性能多路复用技术。这里我将对比一下常见的多路复用技术:select、poll、epoll、kqueue 和 IOCP(Windows)。

小工匠 7043

uniapp - [全端兼容] 高性能 tabbar 底部菜单凸起效果,原生系统自定义底部菜单不卡顿、切换页面不闪烁、自动缓存页面(底部菜单中间自定义一个图片并悬浮起来)

uniapp如何实现底部凸起按钮,uniapptabbar底部菜单怎么自定义,uniapp怎么让底部菜单中间突出来,uniapp自定义底部tabbar,uniapp高性能好用的底部菜单,uniapp自定义底部导航栏并解决闪烁问题,uniapp怎么设置凸起的底部tabbar,uniapp怎么用系统的底部菜单还想让中间的按钮凸起来,uniapp自定义tabbar性能不好怎么办,uni-app自定义导航栏实现中间凸起效果,uniapp底部导航栏中间圆形按钮凸起效果详细代码,uni-app自定义中间图标突起的

🏆 前端领域优质创作者 1万+

Amazon SES 移出沙盒完整指南 & 高通过率模板

AWS SES沙盒模式转正式模式申请指南 申请正式模式需通过AWS审核,常见被拒原因包括邮件用途不清晰、缺少退订机制或发送量不合理。人工申诉需登录AWS Support Center提交服务限额提升请求,填写详细的公司信息、邮件用途及合规措施。 高通过率申诉模板需包含: 公司信息:名称、网址及与AWS的合作情况。 邮件规范:明确类型(交易/营销)、退订链接及退信处理机制。 发送计划:合理预估发送量,确保合规。 关键点:真实信息、用途清晰、退订机制完善、发送量合理。首次被拒可修改后重新提交。

xianyinsuifeng的博客 329

iocp模型

发现Windows下有一种号称性能最好的通信模型,叫做IOCP,中文名称叫做完成端口模型。

前进的博客 2494

Spark中Application、Job、Stage和Task区别详解

在Spark中,有一些关键的概念,如Application、Job、Stage和Task,它们描述了Spark作业的不同层次和组成部分。下面我将详细介绍每个概念,并通过示例说明它们之间的区别。

优快云 精品推荐 902
上一篇: 二叉树的遍历
下一篇: boost应用-替换网页中的超链接
InsideKernel
博客等级 码龄19年 5粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值