使用IOCP时,我应该将WSAOVERLAPPED的hEvent设置为NULL还是设置为WSAEVENT对象的有效句柄?

jpe*_*pen 5 c++ sockets iocp winsock2

根据MSDN:

hEvent:如果在没有I/O完成例程(操作的lpCompletionRoutine参数设置为null)的情况下发出重叠I/O操作,则此参数应包含WSAEVENT对象的有效句柄或为null.

当我使用IOCP时,当我调用WSASend()或WSARecv()时,我将NULL传递给它们的最后一个参数(即lpCompletionRoutine):

WSASend(pIoRequest->GetSocket(), pIoRequest->GetWsaBuffer(), 1, NULL, pIoRequest->GetFlags(), pIoRequest, NULL);

WSARecv(pIoRequest->GetSocket(), pIoRequest->GetWsaBuffer(), 1, NULL, &(pIoRequest->GetFlags()), pIoRequest, NULL);
Run Code Online (Sandbox Code Playgroud)

我的"每个I/O数据"类(pIoRequest)看起来像:

class IoRequest : public WSAOVERLAPPED
{
public:
    IoRequest()
    {
        ...
        SecureZeroMemory(this, sizeof(WSAOVERLAPPED));
        hEvent = WSACreateEvent(); // A
    }
    ...
    void ResetForNextIoRequest()
    {
        WSACloseEvent(hEvent); // B
        SecureZeroMemory(this, sizeof(WSAOVERLAPPED));
        hEvent = WSACreateEvent(); // C
        ...
    }
    ...
    DWORD& GetFlags() { return m_dwFlags; }
    ...
private:
    ...
    DWORD m_dwFlags;
    ...
};
Run Code Online (Sandbox Code Playgroud)

即使我注释掉上面标记为A,B和C的行,它似乎对我的程序的行为没有任何影响.

那么如何决定何时调用WSACreateEvent()或者只是将hEvent设置为NULL?

Amb*_*jak 16

如果您正在使用IOCP,则无需传递事件对象,因为您将使用GetQueuedCompletionStatus()接收完成通知.假设您已使用CreateIoCompletionPort()将套接字与完成端口相关联,这将起作用.

是的,Windows上的I/O令人困惑.特别是,至少有六种不同的方式来使用套接字.首先,你似乎遇到过两个:

  • 使用IOCP重叠I/O(CreateIoCompletionPort,GetQueuedCompletionStatus,WSASend等).这可能是最有效的方法.您可以轻松地将任何类型的事件也集成到事件循环中,这些事件也使用IOCP.对于其他事件,您可以使用PostQueuedCompletionStatus解决方法.这是(AFAIK)唯一可以扩展大量套接字的方法.

  • 没有IOCP的重叠I/O,即使用WSASend和朋友使用事件对象,使用例如WaitForMultipleObjects监视事件,并使用WSAGetOverlappedResult获取结果.这可以相对容易地与任何非套接字I/O集成,也可以映射到HANDLE对象.但是,WaitForMultipleObjects限制为一次监视不超过64个句柄.

还至少还有四个:

  • 阻止调用(send,recv以及WSA*版本).如果你这样做,你就不得不使用线程.这既难以正确实施又可能效率低下.

  • 使用select()的非阻塞套接字.这样做的好处是可以使用与类Unix系统类似的代码.但是,它(AFAIK)不能与插槽以外的I/O集成.

  • 使用WSAEventSelect进行非阻塞.这与select()方法类似,不同之处在于,不是使用select()来获取通知,而是将套接字事件映射到事件对象,并使用例如WaitForMultipleObjects监视那些事件对象.它也类似于没有IOCP方法的重叠,并且受到不超过64个对象的相同限制.

  • 使用WSAAsyncSelect进行非阻塞.这使用Windows消息循环将套接字通知作为消息传递到程序中的窗口.这很容易集成到已经使用消息循环的应用程序中,例如许多GUI应用程序.

如果我遗漏了一些东西,或者如果其中一些实际上不起作用,请纠正我:).