5

根据MSDN

hEvent:如果在没有 I/O 完成例程的情况下发出重叠 I/O 操作(操作的 lpCompletionRoutine 参数设置为 null),则此参数应包含 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);

我的“每个 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;
    ...
};

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

那么您如何决定何时调用 WSACreateEvent() 或简单地将 hEvent 设置为 NULL?

4

1 回答 1

18

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

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

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

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

还有至少四个:

  • 阻塞调用(send、recv 以及 WSA* 版本)。如果你这样做,你将被迫使用线程。这既难以正确实施,也可能效率低下。

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

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

  • Non-blocking using WSAAsyncSelect. This delivers socket notifications as messages to a window within a program using using the Windows message loop. This is easy to integrate into an application already using the message loop, such as many GUI applications.

Correct me if I left something out or if some of this doesn't actually work :).

于 2012-08-06T15:38:53.740 回答