windows完成端口(三)

系列目录 windows完成端口(一) windows完成端口(二) windows完成端口(三) windows完成端口(四) windows完成端口(五) windows完成端口(六)

1

现在还剩下最后一个问题,就是工作线程如何退出。当然你可以在每次判断标识位前先判断一个退出标识。但是如果工作线程正好被GetQueuedCompletionStatus挂载那里呢?如何唤醒,微软提供了另外一个函数:PostQueuedCompletionStatus,看下这个函数的签名:

BOOL WINAPI PostQueuedCompletionStatus(  
  _In_     HANDLE       CompletionPort,  
  _In_     DWORD        dwNumberOfBytesTransferred,  
  _In_     ULONG_PTR    dwCompletionKey,  
  _In_opt_ LPOVERLAPPED lpOverlapped  
);  

这个函数可以唤醒被GetQueuedCompletionStatus函数挂起的工作线程,当然其第三个参数也是一个CompletionKey(dwCompletionKey)。你可以使用这个dwCompletionKey做标识干一些其它的事情,当然设置一个退出码也可以。例如:

PostQueuedCompletionStatus(m_hIOCompletionPort, 0,
                           (DWORD)EXIT_CODE, NULL);  

这样工作线程里面就可以使用EXIT_CODE来作为退出标志:

DWORD ThreadFunction()  
{  
    OVERLAPPED           *pOverlapped = NULL;  
    PER_SOCKET_CONTEXT   *pSocketContext = NULL;  
    DWORD                dwBytesTransfered = 0;  

    BOOL bReturn = GetQueuedCompletionStatus(m_hIOCompletionPort, 
                                             &dwBytesTransfered, 
                                             (PULONG_PTR)&pSocketContext,
                                             &pOverlapped, INFINITE);  

    // 如果收到的是退出标志,则直接退出  
    if ( EXIT_CODE==(DWORD)pSocketContext )  
    {  
        return 0;  
    }  

    if (((SOME_STRUCT*)pSocketContext)->s == 侦听socket句柄)  
    {  
        /*连接成功后可以做以下事情:  
         1. 获取对端和本端的ip地址和端口号,
            即AcceptEx的第三个参数lpOutputBuffer中拿
            (这一步,不是必须)  
         2. 如果对端连接成功后会发数据过来,
            则可以从初始化时调用AcceptEx准备的缓冲区里面拿到
            即AcceptEx的第三个参数lpOutputBuffer中拿
           (这一步不是必须)  

         3. 再次调用AcceptEx补充一个sAcceptSocket
           (这一步是必须的)  

         4. 调用WSASend准备发送数据工作
            或调用WSARecv准备接收数据工作(这一步,不是必须)*/ 
    }  
    //普通客户端socket收发数据  
    else  
    {  
        //通过pOverlapped结构得到pIOContext  
        PER_IO_CONTEXT* pIOContext = (PER_IO_CONTEXT*)pOverlapped;    
        if (pIOContext->Type == 收)  
        {             
            //解析收到的数据(这一步,不是必须)  
            //调用WSASend准备发送数据工作(比如应答客户端)(这一步,不是必须)  
            //继续调用WSARecv准备收取数据工作(这一步,不是必须)  
        }  
        else if (pIOContext->Type == 发)  
        {  
            //调用WSARecv准备收取数据工作(这一步,不是必须)  
        }  
    }  

    return 0;  
}  

至此,关于完成端口的东西就全部介绍完了。我们小结一下,掌握完成端口的关键在于理解以下几点:

  1. 完成端口绑定了某个socket后,不仅其事件的读写检测由操作系统完成,而且就算是接受新连接、收发数据的动作也是由操作系统代劳了,操作系统完成后会通知你。等你收到通知时,一切都完成好了。你可以直接取出对应的数据使用。
  2. 要想第1点介绍的事情由操作系统代劳,你必须预先准备很多数据结构,比如两端的地址结构体、收发缓冲区、和用来表示新连接的socket等等,这些准备工作可能在程序初始化阶段,也可能在工作线程某个事件处理的地方。
  3. 初始化准备好的各种缓冲区如何在工作线程里面引用到的关键就在于绑定完成端口时CompletionKey和准备收发缓冲区时OVERLAPPED结构体的使用, CompletionKey对应PER Socket Data, OVERLAPPED对应Per IO Data,即CompletionKey是单Socket数据,OVERLAPPED是单IO数据。

由于公众号文章字数有限,您可以接着阅读下一篇:《windows完成端口(四)》 系列目录 windows完成端口(一) windows完成端口(二) windows完成端口(三) windows完成端口(四) windows完成端口(五) windows完成端口(六)

原文发布于微信公众号 - 高性能服务器开发(easyserverdev)

原文发表时间:2018-04-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏乐沙弥的世界

Vmware server 下为Oracle RAC 添加共享磁盘

    在VMware下的Oracle RAC 环境中,对于共享存储不够或者需要增加新的共享磁盘来配置ocr或votingdisk的多路镜像,我们可以通过vmw...

22810
来自专栏程序源代码

python学习手册-环境安装和配置

导读 | python学习手册 ? 一、python 安装和配置 下载安装包 首先需要在官网 https://www.python.org/ 下载pyth...

39940
来自专栏FreeBuf

Office文档嵌入对象点击执行的社工技巧

Microsoft Office相信大家都用过。Office在文档中嵌入对象极大的方便了我们的日常使用,但同时也为我们带来了众多安全问题。可以说,Office文...

20060
来自专栏落影的专栏

CocoaPods移除和XCode子工程依赖图文教程

本文以GPUImage的工程为示例,去除管理依赖的CocoaPods,改用子工程依赖的方式。目的就是复用代码,多个工程可以使用同一份GPUImage的代码。 1...

37870
来自专栏张善友的专栏

冗余代码检查工具Simian

微软web2.0开发示例Kobe,重蹈了Oxite的覆辙。Ayende连续发表了五篇高质量的Kobe探讨贴: Kobe – In the nuts & bolt...

38680
来自专栏张善友的专栏

通过ProGet搭建一个内部的Nuget服务器

.NET Core项目完全使用Nuget 管理组件之间的依赖关系,Nuget已经成为.NET 生态系统中不可或缺的一个组件,从项目角度,将项目中各种组件的引用统...

301110
来自专栏24K纯开源

Premiere Pro & After Effects插件开发调试方法

      在给Adobe Premiere Pro(PR)和Adobe After Effects(AE)插件开发时,对于实时调试插件有着很强的需求。除了业务...

30170
来自专栏LuckQI

Linux学习桌面系统生成快捷方式与普通用户权限

说了这么多其实还是建议如果有环境的话,程序员还是在Linux环境下开发的好。虽然刚开始有点难,但是后面会发现有很多好处。那么我们在Linux系统下开发首先会遇到...

11000
来自专栏ASP.NETCore

微软为.NET程序员带来了最优的跨平台开发体验-WSL

在前几个Visual Studio Code更新中发现有一个重要得特性,就是nodejs可以使用VS Code在WSL中进行Debug了(WSL是指Win10中...

12940
来自专栏蓝天

UNIX和Linux信号

1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的),编号为32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区...

25340

扫码关注云+社区

领取腾讯云代金券