集成 IOCP 到 Libevent

集成 IOCP 到 Libevent

完整的代码在
http://spserver.googlecode.com/files/libevent-1.4.4-iocp-3.zip

2008.08.23
http://spserver.googlecode.com/files/libevent-1.4.5-stable-iocp-2.zip
增加了 non-blocking connect 的支持。

IOCP 是真正的异步 IO ,Libevent 提供的是一个 event-driven 的接口。

异步 IO 和 event-driven 的区别:
1.对于 event-driven,需要等待内核通知我们去启动一个IO操作,然后直接得到IO操作的结果
2.对于异步IO,我们可以随时无阻塞地启动 IO,然后由内核通知我们 IO 操作何时完成

要把 IOCP 集成到 libevent ,基本的思路是用 IOCP 模拟 event-driven 接口。
在 IOCP 中有一个特性,刚好可以用来模拟 event-driven 的接口:zero byte buffer recv/send。

当我们发起 WSARecv,WSASend 的时候,需要用 WSABUF 传递一个 buffer 进去。
如果我们把这个 buffer 设置为 zero byte ,那么当 socket 可读,或者可写的时候,
通过 GQCS 同样可以得到结果。这样就等于是模拟了 event-driven 的接口。

另一方面,Windows 的 WSAEventSelect 函数提供了一个 event-driven 的 accept 功能。

...
WSAEventSelect( listenFd, hEvent, FD_ACCEPT );
...


问题在于如何把 IOCP 和 WSAEventSelect 集成起来。

通过查看 WSARecv,WSASend 的接口,可以注意到这两个接口都需要提供一个 OVERLAPPED 的结构体。
在这个结构体里有一个 hEvent 的成员。如果设置了这个 hEvent 参数,那么当这个 IO 请求完成的时候,
hEvent 将会被 signal 。详细信息可以参考下面这个 URL :

http://msdn.microsoft.com/en-us/library/ms742203(VS.85).aspx
引用
If the lpCompletionRoutine parameter is NULL, the hEvent parameter of lpOverlapped is signaled when the overlapped operation completes if it contains a valid event object handle. An application can use WSAWaitForMultipleEvents or WSAGetOverlappedResult to wait or poll on the event object.


这样看起来可以通过 WSAWaitForMultipleEvents 来集成 IOCP 和 WSAEventSelect 。
1.用 WSAEventSelect 来处理 accept event
2.用 IOCP 来处理 recv/send event ,发起 recv/send 请求的时候,设置 OVERLAPPED 的 hEvent 参数
3.把 WSAEventSelect 的 hEvent 和 IOCP 的 hEvent 收集起来,用 WSAWaitForMultipleEvents 统一处理

需要注意的时候,上述的第二步中,不需要为每个 recv/send 请求生成一个新的 hEvent,
而是所有的 recv/send 共用一个 hEvent 就行了。

在下面这个 URL 中提到,对于一个 hEvent 如果已经是 signal ,再次 signal ,不会有副作用。
http://msdn.microsoft.com/en-us/library/ms686211(VS.85).aspx
引用
Setting an event that is already set has no effect.



用代码来描述上面的这个思路,大概是下面这样。
首先创建 64 个 hEvent ,其中的 objects[0] 就用于 IOCP 中所有的 IO 操作。
其他剩余的 63 个 hEvent ,就可以用于 accept event 。
程序首先调用 WSAWaitForMultipleEvents 来等待 event 发生。
如果发现是 objects[0] 有事件,那么是 IOCP 的 IO 操作已经有完成的,就调用 GQCS 来处理。
如果发现是其他的 objects 有事件,那么就是有 accept event 发生。

/* objects[0] for iocp operations, object[1..63] for accept */
HANDLE objects[64];
struct event * accepts[64];
 
struct win32iocp_event event1;
event1.overlapped.hEvent = objects[0];
WSARecv( ..., &event1.overlapped, ... );
....
 
struct win32iocp_event event2;
event2.overlapped.hEvent = objects[0];
WSASend( ..., &event2.overlapped, ... );
...
 
WSAEventSelect( ev1->ev_fd, objects[1], FD_ACCEPT );
accepts[1] = ev1;
...
 
WSAEventSelect( ev2->ev_fd, objects[2], FD_ACCEPT );
accepts[2] = ev2;
...
 
int index = WSAWaitForMultipleEvents( 64, objects, FALSE, timeout, FALSE );
index = index - WSA_WAIT_EVENT_0;
 
if( index > 0 ) {
 struct event * event = win32iocp_op->accepts[index];
 event_active (event, EV_READ | EV_ACCEPT, 1);
}
 
if( index == 0 ) {
 for( ; ; ) {
  GetQueuedCompletionPort( ...... );
 }
}
 

你可能感兴趣的:(windows,linux,socket,memcached,单元测试)