2012-08-06 57 views
4

MSDN使用IOCP時,我應該將WSAOVERLAPPED的hEvent設置爲NULL還是設置爲WSAEVENT對象的有效句柄?

hEvent:如果I/O操作是沒有I/O 完成例程發出(操作的用lpCompletionRoutine參數是 設置爲null)的重疊,那麼這個參數要麼包含一個到WSAEVENT對象的有效句柄 或爲空。

由於我使用的是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?

回答

14

如果您使用的是IOCP,則不需要傳遞事件對象,因爲您將使用GetQueuedCompletionStatus()接收完成通知。假設您已使用CreateIoCompletionPort()將套接字與完成端口相關聯,這將工作。

是的,Windows上的I/O很混亂。尤其是,至少有不同的方式來使用套接字。首先,你似乎是兩所遇到:

  • 重疊I/O使用IOCP(CreateIoCompletionPort,GetQueuedCompletionStatus時,WSASend等)。 這可能是最有效的方法。您可以輕鬆地將事件循環集成到任何也使用IOCP的事件中。對於其他事件,您可以使用PostQueuedCompletionStatus解決該問題。這是(AFAIK)唯一能夠擴展大量套接字的方法。

  • 沒有IOCP的重疊I/O,即使用WSASend和具有事件對象的朋友,使用例如事件對象監視事件。 WaitForMultipleObjects,並使用WSAGetOverlappedResult獲得結果。這與任何也可以映射到HANDLE對象的非套接字I/O相結合是相對容易的。但是,WaitForMultipleObjects一次只能監視不超過64個句柄。

和至少四個:

  • 阻塞調用(發送,recv的,也是WSA *版本)。如果你這樣做,你不得不使用線程。這很難正確實施,可能效率低下。

  • 使用非阻塞插座select()。這樣做的好處是可以使用類似於unix類系統上的代碼。但是,它(AFAIK)不能與套接字以外的I/O集成。

  • 非阻塞使用WSAEventSelect。這與select()方法類似,不同之處在於,不是使用select()來獲取通知,而是將套接字事件映射到事件對象,並使用例如WaitForMultipleObjects。它也類似於沒有IOCP方法的重疊,並且受限於不超過64個對象的相同限制。

  • 非阻塞使用WSAAsyncSelect。這使用Windows message loop將套接字通知作爲消息傳送到程序中的窗口。這很容易集成到已經使用消息循環的應用程序中,例如許多GUI應用程序。

糾正我,如果我留下了一些東西,或者如果這其中一些實際上不工作:)。

+0

Ambroz-謝謝澄清。我可以再問一個問題嗎?在「IoRequest」中有「DWORD m_dwFlags」是否有意義(請參閱上面的編輯代碼)?我可以在我的工作線程中創建一個基於堆棧的DWRD dwFlags,並將它傳遞給WSASend()和WSARecv()? – jpen 2012-08-06 16:07:31

+0

您似乎可以將它放在堆棧上,並在操作正在進行時讓它超出範圍。從WSARecv頁面:「在這種情況下,lpNumberOfBytesRecvd和lpFlags不會更新」。 WSASend沒有這個問題,因爲它只是取值而不是指針。 – 2012-08-06 16:12:27

相關問題