王朝网络
分享
 
 
 

Overlapped模型与CompletionPort模型,摘自《Visual C++网络游戏建模与实现》(苏羽、王媛媛编著)

王朝vc·作者佚名  2006-01-10
宽屏版  字体: |||超大  

Win32重叠I/O(Overloapped I/O)机制允许发起一个操作,然后在操作完成之后接受

到信息。对于那种需要很长时间才能完成的操作来说,重叠I/O机制尤其有用,因为发起

重叠操作的线程在重叠请求发出后就可以自由地做别的事情了。

在Windows NT/2000上,提供真正可扩展的I/O模型就是使用完成端口(Completion

Port)的重叠I/O。

……

可以把完成端口看成系统维护的一个队列,操作系统把重叠I/O操作完成的事件通知

放到该队列里,由于是暴露“操作完成”的事件通知,所以命名为“完成端口”(Completion

Ports)。一个Socket被创建后,可以在任何时刻和一个完成端口联系起来。

一般来说,一个应用程序可以创建多个工作线程来处理完成端口上的通知事件。工作

线程的数量依赖于程序的具体需要。但是在理想的情况下,应该对应一个CPU创建一个线

程。因为在完成端口理想模型中,每个线程都可以从系统获得一个“原子”性的时间片,轮

番运行并检查完成端口,线程的切换是额外的开销。在实际开发的时候,还要考虑这些线

程是否牵涉到其他堵塞操作的情况。如果某线程进行堵塞操作,系统则将其挂起,让别的

线程获得运行时间。因此,如果有这样的情况,可以多创建几个线程来尽量利用时间。

应用完成端口分两步走:

1. 创建完成端口句柄:

HANDLE hIocp;

hIocp=CreateIoCompletionPort(

INVALID_HANDLE_VALUE,

NULL,

(ULONG_PTR)0,

0);

if(hIocp==NULL) {

//如果错误

……

}

注意在第1个参数(FileHandle)传入INVALID_FILE_HANDLE,第2个参数(ExistingCompletionPort)

传入NULL,系统将创建一个新的完成端口句柄,没有任何I/O句柄与其关联。

2. 完成端口创建成功后,在Socket和完成端口之间建立关联。再次调用CreateIoCompletionPort

函数,这一次在第1个参数FileHandle传入创建的Socket句柄,参数ExistingCompletionPort

为已经创建的完成端口句柄。

以下代码创建了一个Socket并把它和完成端口联系起来。

SOCKET s;

s=Socket(AF_INET,SOCK_STREAM,0);

if(s==INVALID_SOCKET) {

if(CreateIoCompletionPort((HANDLE)s,

hIocp,

(ULONG_PTR)0,

0)==NULL)

{

//如果创建失败

……

}

}

到此为止,Socket已经成功和完成端口相关联。在此Socket进行的重叠I/O操作结果均

使用完成端口发出通知。

注意:CreateIoCompletionPort函数的第3个参数允许开发人员传入一个类型为ULONG_PTR

的数据成员,我们把它称为完成键(Completion Key),此数据成员可以设计为指向包含Socket

信息的一个结构体的一个指针,用来把相关的环境信息和Socket联系起来,每次完成通知来

到的同时,该环境信息也随着通知一起返回给开发人员。

完成端口创建以及与Socket关联之后,就要创建一个或多个工作线程来处理完成通知,

每个线程都可以循环地调用GetQueuedCompletionStatus函数,检查完成端口上的通知事件。

在举例说明一个典型的工作线程之前,我们先讨论一下重叠I/O的过程。到一个重叠I/O

被发起,一个Overlapped结构体的指针就要作为参数传递给系统。当操作完成时,

GetQueueCompletionStatus就可以返回指向同一个Overlapped结构的指针。为了辨认和定位

这个已完成的操作,开发人员最好定义自己的OVERLAPPED结构,以包含一些自己定义的关于

操作本身的额外信息。比如:

typedef struct _OVERLAPPELUS {

OVERLAPPED ol;

SOCKET s, sclient;

int OpCode;

WSABUF wbuf;

DWORD dwBytes, dwFlags;

} OVERLAPPELUS;

此结构的第1个成员为默认的OVERLAPPED结构,第2和第3个为本地服务Socket和与该

操作相关的客户socket,第4个成员为操作类型,对于Socket,现在定义的有以下3种:

#define OP_READ 0

#define OP_WRITE 1

#define OP_ACCEPT 2

然后还有应用程序的Socket缓冲区,操作数据量,标志位以及其他开发人员认为有用

的信息。

当进行重叠I/O操作,把OVERLAPPELUS结构作为重叠I/O的参数lpOverlapp传递(如

WSASend,WASRecv,等函数的lpOverlapped参数,要求传入一个OVERLAPP结构的指针)。

当操作完成后,GetQueuedCompletionStatus函数返回一个LPOVERLAPPED类型的指针,

这个指针其实是指向开发人员定义的扩展OVERLAPPELUS结构,包含着开发人员早先传入的

全部信息。

注意:OVERLAPPED成员不一定要求是OVERLAPPELUS扩展结构的一个成员,在获得

OVERLAPPED指针之后,可以用CONTAINING_RECORD宏获得相应的扩展结构的指针。

典型的Worker Thread结构:

DWORD WINAPI WorkerThread(LPVOID lpParam)

{

ULONG_PTR *PerHandleKey;

OVERLAPPED *Overlap;

OVERLAPPELUS *OverlapPlus, *newolp;

DWORD dwBytesXfered;

while(1)

{

ret=GetQueuedCompletionStatus(

hIocp,

&dwBytesXfered,

(PULONG_PTR)&PerHandleKey,

&Overlap,

INFINITE);

if(ret==0)

{

//如果操作失败

continue;

}

OverlapPlus=CONTATING_RECORD(Overlap, OVERLAPPELUS, ol);

switch(OverlapPlus->OpCode)

{

case OP_ACCEPT:

CreateIoCompletionPort(

(HANDLE)OverlapPlus->sclient,

hIocp,

(ULONG_PTR)0,

0);

newolp=AllocateOverlappelus();

newolp->s=OverlapPlus->sclient;

newolp->OpCode=OP_READ;

PrepareSendBuffer(&newolp->wbuf);

ret=WSASend(

newolp->s,

&newolp->wbuf,

1,

&newolp->dwBytes,

0,

&newolp.ol,

NULL);

if(ret==SOCKET_ERROR)

{

if(WSAGetLastError()!=WSA_IO_PENDING)

{

//进行错误处理

……

}

}

FreeOverlappelus(OverlapPlus);

SetEvent(hAcceptThread);

break;

case OP_READ:

memset(&OverlapPlus->ol,0,sizeof(OVERLAPPED));

ret=WSARecv(

OverlapPlus->s,

&OverlapPlus->wbuf,

1,

&OverlapPlus->dwBytes,

&OverlapPlus->dwFlags,

&OverlapPlus->ol,

NULL);

if(ret==SOCKET_ERROR)

{

if(WSAGetLastError()!=WSA_IO_PENDING)

{

//错误处理

……

}

}

break;

case OP_WRITE:

break;

}/*switch结束*/

}/*while结束*/

}/*WorkerThread结束*/

注意:如果Overlapped操作立刻失败(比如,返回SOCKET_ERROR或其他非

WSA_IO_PENDING的错误),则没有任何完成通知事件会被放到完成端口队列里。反之,

则一定有相应的通知事件被放到端口队列。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有