`
阿尔萨斯
  • 浏览: 4472050 次
社区版块
存档分类
最新评论

Windows完成端口编程

 
阅读更多

Windows完成端口编程

目录:

Windows完成端口编程... 1

目录:... 1

基本概念... 1

OVERLAPPED数据结构... 1

完成端口的内部机制... 2

创建完成端口... 2

完成端口线程的工作原理... 3

线程间数据传递... 4

线程的安全退出... 4

基本概念

设备---windows操作系统上允许通信的任何东西,比如文件、目录、串行口、并行口、邮件槽、命名管道、无名管道、套接字、控制台、逻辑磁盘、物理磁盘等。绝大多数与设备打交道的函数都是CreateFile/ReadFile/WriteFile等。所以我们不能看到**File函数就只想到文件设备。

与设备通信有两种方式,同步方式和异步方式。同步方式下,当调用ReadFile函数时,函数会等待系统执行完所要求的工作,然后才返回;异步方式下,ReadFile这类函数会直接返回,系统自己去完成对设备的操作,然后以某种方式通知完成操作。

重叠I/O----顾名思义,当你调用了某个函数(比如ReadFile)就立刻返回做自己的其他动作的时候,同时系统也在对I/0设备进行你要求的操作,在这段时间内你的程序和系统的内部动作是重叠的,因此有更好的性能。所以,重叠I/O是用于异步方式下使用I/O设备的。

重叠I/O需要使用的一个非常重要的数据结构OVERLAPPED

完成端口---是一种WINDOWS内核对象。完成端口用于异步方式的重叠I/0情况下,当然重叠I/O不一定非使用完成端口不可,还有设备内核对象、事件对象、告警I/0等。但是完成端口内部提供了线程池的管理,可以避免反复创建线程的开销,同时可以根据CPU的个数灵活的决定线程个数,而且可以让减少线程调度的次数从而提高性能。

OVERLAPPED数据结构

typedef struct _OVERLAPPED {

ULONG_PTR Internal;//被系统内部赋值,用来表示系统状态

ULONG_PTR InternalHigh;// 被系统内部赋值,传输的字节数

union {

struct {

DWORD Offset;//和OffsetHigh合成一个64位的整数,用来表示从文件头部的多少字节开始

DWORD OffsetHigh;//操作,如果不是对文件I/O来操作,则必须设定为0

};

PVOID Pointer;

};

HANDLE hEvent;//如果不使用,就务必设为0,否则请赋一个有效的Event句柄

} OVERLAPPED, *LPOVERLAPPED;

下面是异步方式使用ReadFile的一个例子

OVERLAPPED Overlapped;

Overlapped.Offset=345;

Overlapped.OffsetHigh=0;

Overlapped.hEvent=0;

//假定其他参数都已经被初始化

ReadFile(hFile,buffer,sizeof(buffer),&dwNumBytesRead,&Overlapped);

这样就完成了异步方式读文件的操作,然后ReadFile函数返回,由操作系统做自己的事情吧

下面介绍几个与OVERLAPPED结构相关的函数

等待重叠I/0操作完成的函数

BOOL GetOverlappedResult (

HANDLE hFile,

LPOVERLAPPED lpOverlapped,//接受返回的重叠I/0结构

LPDWORD lpcbTransfer,//成功传输了多少字节数

BOOL fWait //TRUE只有当操作完成才返回,FALSE直接返回,如果操作没有完成,通过调//GetLastError ( )函数会返回ERROR_IO_INCOMPLETE

);

HasOverlappedIoCompleted可以帮助我们测试重叠I/0操作是否完成,该宏对OVERLAPPED结构的Internal成员进行了测试,查看是否等于STATUS_PENDING值。

完成端口的内部机制

创建完成端口

完成端口是一个内核对象,使用时他总是要和至少一个有效的设备句柄进行关联,完成端口是一个复杂的内核对象,创建它的函数是:

HANDLE CreateIoCompletionPort(

IN HANDLE FileHandle,

IN HANDLE ExistingCompletionPort,

IN ULONG_PTR CompletionKey,

IN DWORD NumberOfConcurrentThreads

);

通常创建工作分两步:

第一步,创建一个新的完成端口内核对象,可以使用下面的函数:

HANDLE CreateNewCompletionPort(DWORD dwNumberOfThreads)

{

return CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,dwNumberOfThreads);

};

第二步,将刚创建的完成端口和一个有效的设备句柄关联起来,可以使用下面的函数:

bool AssicoateDeviceWithCompletionPort(HANDLE hCompPort,HANDLE hDevice,DWORD dwCompKey)

{

HANDLE h=CreateIoCompletionPort(hDevice,hCompPort,dwCompKey,0);

return h==hCompPort;

};

说明

1) CreateIoCompletionPort函数也可以一次性的既创建完成端口对象,又关联到一个有效的设备句柄

2) CompletionKey是一个可以自己定义的参数,我们可以把一个结构的地址赋给它,然后在合适的时候取出来使用,最好要保证结构里面的内存不是分配在栈上,除非你有十分的把握内存会保留到你要使用的那一刻。

3) NumberOfConcurrentThreads通常用来指定要允许同时运行的的线程的最大个数。通常我们指定为0,这样系统会根据CPU的个数来自动确定。

创建和关联的动作完成后,系统会将完成端口关联的设备句柄、完成键作为一条纪录加入到这个完成端口的设备列表中。如果你有多个完成端口,就会有多个对应的设备列表。如果设备句柄被关闭,则表中自动删除该纪录。

完成端口线程的工作原理

完成端口可以帮助我们管理线程池,但是线程池中的线程需要我们使用_beginthreadex来创建,凭什么通知完成端口管理我们的新线程呢?答案在函数GetQueuedCompletionStatus。该函数原型:

BOOL GetQueuedCompletionStatus(

IN HANDLE CompletionPort,

OUT LPDWORD lpNumberOfBytesTransferred,

OUT PULONG_PTR lpCompletionKey,

OUT LPOVERLAPPED *lpOverlapped,

IN DWORD dwMilliseconds

);

这个函数试图从指定的完成端口的I/0完成队列中抽取纪录。只有当重叠I/O动作完成的时候,完成队列中才有纪录。凡是调用这个函数的线程将被放入到完成端口的等待线程队列中,因此完成端口就可以在自己的线程池中帮助我们维护这个线程。

完成端口的I/0完成队列中存放了当重叠I/0完成的结果---- 一条纪录,该纪录拥有四个字段,前三项就对应GetQueuedCompletionStatus函数的2、3、4参数,最后一个字段是错误信息dwError。我们也可以通过调用PostQueudCompletionStatus模拟完成了一个重叠I/0操作。

I/0完成队列中出现了纪录,完成端口将会检查等待线程队列,该队列中的线程都是通过调用GetQueuedCompletionStatus函数使自己加入队列的。等待线程队列很简单,只是保存了这些线程的ID。完成端口会按照后进先出的原则将一个线程队列的ID放入到释放线程列表中,同时该线程将从等待GetQueuedCompletionStatus函数返回的睡眠状态中变为可调度状态等待CPU的调度。

基本上情况就是如此,所以我们的线程要想成为完成端口管理的线程,就必须要调用

GetQueuedCompletionStatus函数。出于性能的优化,实际上完成端口还维护了一个暂停线程列表,具体细节可以参考《Windows高级编程指南》,我们现在知道的知识,已经足够了。

线程间数据传递

线程间传递数据最常用的办法是在_beginthreadex函数中将参数传递给线程函数,或者使用全局变量。但是完成端口还有自己的传递数据的方法,答案就在于CompletionKeyOVERLAPPED参数。

CompletionKey被保存在完成端口的设备表中,是和设备句柄一一对应的,我们可以将与设备句柄相关的数据保存到CompletionKey中,或者将CompletionKey表示为结构指针,这样就可以传递更加丰富的内容。这些内容只能在一开始关联完成端口和设备句柄的时候做,因此不能在以后动态改变。

OVERLAPPED参数是在每次调用ReadFile这样的支持重叠I/0的函数时传递给完成端口的。我们可以看到,如果我们不是对文件设备做操作,该结构的成员变量就对我们几乎毫无作用。我们需要附加信息,可以创建自己的结构,然后将OVERLAPPED结构变量作为我们结构变量的第一个成员,然后传递第一个成员变量的地址给ReadFile函数。因为类型匹配,当然可以通过编译。当GetQueuedCompletionStatus函数返回时,我们可以获取到第一个成员变量的地址,然后一个简单的强制转换,我们就可以把它当作完整的自定义结构的指针使用,这样就可以传递很多附加的数据了。太好了!只有一点要注意,如果跨线程传递,请注意将数据分配到堆上,并且接收端应该将数据用完后释放。我们通常需要将ReadFile这样的异步函数的所需要的缓冲区放到我们自定义的结构中,这样当GetQueuedCompletionStatus被返回时,我们的自定义结构的缓冲区变量中就存放了I/0操作的数据。

CompletionKeyOVERLAPPED参数,都可以通过GetQueuedCompletionStatus函数获得。

线程的安全退出

很多线程为了不止一次的执行异步数据处理,需要使用如下语句

while (true)

{

.。。。。。。

GetQueuedCompletionStatus(...);

。。。。。。

}

那么如何退出呢,答案就在于上面曾提到的PostQueudCompletionStatus函数,我们可以用它发送一个自定义的包含了OVERLAPPED成员变量的结构地址,里面包含一个状态变量,当状态变量为退出标志时,线程就执行清除动作然后退出。

分享到:
评论

相关推荐

    WINDOWS完成端口编程IOCP&&THREADPOOL

    WINDOWS完成端口编程 1、基本概念 2、WINDOWS完成端口的特点 3、完成端口(Completion Ports )相关数据结构和创建 4、完成端口线程的工作原理 5、Windows完成端口的实例代码

    Windows_IO完成端口编程

    Windows完成端口编程是一种强大的技术,它为开发者提供了一种有效的方法来处理高并发网络请求。通过利用系统内部的线程池管理和高效的事件通知机制,可以在Windows平台上构建出性能优异的服务端应用。掌握这一技术...

    windows socket网络编程之iocp完成端口模型的例子

    在Windows Socket(Winsock)网络编程中,I/O完成端口(I/O Completion Port, IOCP)是一种高效处理大量并发I/O操作的机制。本文将深入探讨IOCP完成端口模型,并通过具体例子来阐述其工作原理和实现方法。 IOCP是...

    windows TCP/IP 网络编程(七)5种windows网络模型(5)完成端口

    在Windows平台上进行TCP/IP网络编程时,我们常常会遇到各种网络模型的选择,其中“完成端口”(IO Completion Ports, I/OCP)是高级网络服务的一种,尤其适用于高并发的服务器应用。本篇将深入探讨完成端口的概念、...

    网络服务端_完成端口编程_彩票分析软件服务端

    《网络服务端_完成端口编程_彩票分析软件服务端》 在当今信息化时代,网络服务端编程扮演着至关重要的角色。本项目是23vs彩票分析软件的服务端部分,其核心亮点在于采用VC++进行完成端口(Completion Port)多线程...

    IOCP完成端口编程

    总的来说,IOCP完成端口编程是Windows平台下进行高性能网络编程的重要技术,它通过异步I/O和线程池管理,为大规模并发提供了强大的支撑。学习和掌握IOCP编程,对于提升Windows服务器应用的性能和稳定性至关重要。

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

    作者慷慨地分享了这个资源,旨在让读者能动手实践,增强对完成端口编程的理解。 【标签】"完成端口 源码 PiggyX" 高亮了本篇内容的核心元素:完成端口的实现代码以及与"PiggyX"相关的应用。通过阅读源码,我们可以...

    vc 完成端口实例

    完成端口(IO Completion Port,简称IOCP)是一种高级的I/O模型,它在Windows操作系统中被广泛用于实现多线程并行处理I/O操作,从而极大地提高了程序的效率。本文将深入探讨VC++中使用完成端口的实例,以及它如何...

    CompletionPort 完成端口编程实例

    总结来说,完成端口编程是一种优化的异步I/O模型,通过结合线程池和异步I/O操作,可以高效地处理大量并发连接。这个实例提供了C++实现服务端和客户端的参考,有助于开发者理解和掌握这种高级的网络编程技术。

    vc 下 完成端口的实现例子

    在Windows系统中,完成端口(Completion Port,简称CP)是一种高效的I/O多路复用技术,常用于处理大量并发的网络请求。本文将详细解释如何在Visual C++(vc)环境下实现完成端口,以及如何通过提供的`...

    完成端口源码vc6.0

    在Windows系统中,完成端口(Completion Port,简称I/O Completion Ports,IOCP)是一种高效且可扩展的I/O模型,常用于多线程服务,尤其是网络编程中。完成端口能够有效地处理大量并发连接,它通过将I/O操作与执行...

    IOPC完成端口编程自己总结(包含源码)

    根据给定的信息,本文将详细解释“IOPC完成端口编程”的核心概念、流程与应用场景,特别是基于所提供的代码示例来展开。 ### IOPC完成端口编程概述 完成端口(I/O Completion Ports,简称IOPC)是Windows操作系统...

    手把手教你玩转网络编程模型之完成端口(CompletionPort)篇

    完成端口的引入,为Windows平台上的网络编程提供了一种全新的视角和方法论,极大地提升了服务器软件的设计灵活性和性能上限。通过深入理解完成端口的工作原理和实践技巧,开发者可以构建出更加高效、稳定、可扩展的...

    完成端口(Completion Port)详解

    完成端口(Completion Port,简称IOCP)是Windows操作系统中的一种高级I/O模型,它用于高效地处理大量的并发I/O操作。在TCP/IP编程中,尤其是服务器应用,高并发是常见的需求,IOCP通过异步I/O和事件通知机制,为...

    《完成端口(CompletionPort)详解》源码

    《完成端口(Completion Port, 简称IOCP)详解》源码是关于网络编程中一种高效异步I/O模型的技术实现。IOCP,即完成端口,是Windows操作系统提供的一种多线程并行处理I/O操作的机制,特别适用于高并发、低延迟的服务器...

    完成端口(IOCP) 服务器源码

    4. 创建IO完成端口,将socket绑定到IO完成端口上 5. 根据当前机器CPU个数创建工作者线程池 6. 使用AcceptEx()提前创建客户socket,创建个数与CPU个数相关 以上准备工作全部完成 7. 工作者线程池 ...

    手把手教你玩转网络编程模型之完成端口(CompletionPort)篇[归纳].pdf

    【完成端口(Completion Port)】是Windows操作系统中一种高效的网络编程模型,尤其适用于构建高并发的C/S架构服务器。本文档将详细讲解完成端口的各个方面,包括其优点、工作原理、API使用、实现机制以及实际应用中的...

    Windows网络编程.pdf

    网络编程概念是学习网络编程的基础,包括阻塞和非阻塞编程模式、Select 模型、WSAAsyncSelect 模型、IO 重叠模型、完成端口模型等。了解这些概念可以帮助开发者更好地开发网络应用程序。 学习资源 学习 Windows ...

    windows编程下的完成端口标准模板,移植性很高

    在Windows编程中,完成端口(Completion Port,简称IOCP)是一种高级的多线程并发I/O模型,它提供了一种高效、可扩展的方式来进行异步I/O操作。完成端口的标准模板通常是为了提高代码的复用性和移植性,使得在不同的...

Global site tag (gtag.js) - Google Analytics