2010-06-11 102 views
0

我正在編寫使用IO完成端口的多線程客戶端。多線程IOCP客戶端問題

我創建並連接了具有WSA_FLAG_OVERLAPPED屬性集的套接字。

if ((m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) 
{ 
    throw std::exception("Failed to create socket."); 
} 

if (WSAConnectByName(m_socket, L"server.com", L"80", &localAddressLength, reinterpret_cast<sockaddr*>(&localAddress), &remoteAddressLength, &remoteAddress, NULL, NULL) == FALSE) 
{ 
    throw std::exception("Failed to connect."); 
} 

我的IO完成端口與插座關聯。

if ((m_hIOCP = CreateIoCompletionPort(reinterpret_cast<HANDLE>(m_socket), m_hIOCP, NULL, 8)) == NULL) 
{ 
    throw std::exception("Failed to create IOCP object."); 
} 

在我嘗試通過套接字發送一些數據之前,所有內容似乎都很順利。

SocketData* socketData = new SocketData; 
socketData->hEvent = 0; 

DWORD bytesSent = 0; 
if (WSASend(m_socket, socketData->SetBuffer(socketData->GenerateLoginRequestHeader()), 1, &bytesSent, NULL, reinterpret_cast<OVERLAPPED*>(socketData), NULL) == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING) 
{ 
    throw std::exception("Failed to send data."); 
} 

WSASend不會返回SOCKET_ERROR,而是將上一個錯誤設置爲WSA_IO_PENDING,WSASend會立即返回。

我需要IO掛起,並完成處理我的線程函數,這也是我的工作線程。

unsigned int __stdcall MyClass::WorkerThread(void* lpThis) 
{ 

} 

我之前已經這樣做了,但我不知道什麼是在這種情況下會錯了,我會非常感謝幫助我解決這個問題的任何努力。

回答

2

這不是一個問題,除非你這樣做。

只要你沒有調用SetFileCompletionNotificationModes()並設置標誌跳過成功完成端口處理,那麼即使WSARecv(或其他)返回SUCCESS,IO完成數據包也會排隊到IOCP,就像返回ERROR_IO_PENDING一樣。因此,您不需要對非錯誤返回情況進行特殊處理。

有關詳細信息,請參見http://support.microsoft.com/default.aspx?scid=kb;en-us;Q192800

+0

那麼問題是,WSARecv立即返回,而不是張貼到IOCP隊列。返回的最後一個錯誤是0,因爲它應該是ERROR_IO_PENDING。我通過使用ConnectEx而不是WSAConnect解決了問題。感謝您的回覆:) – Carl 2010-06-14 10:42:31

+0

我的觀點是,WSARecv CAN LEGALLY返回0,IT STILL以與返回ERROR_IO_PENDING時相同的方式發佈IO完成,除非您通過調用SetFleCompletionNotificationModes()來調整它的工作方式你告訴它不要在它返回成功時發佈一個IO完成......如果你已經用適當的標誌調用SetFileCompletionNotificationModes(),你只需要有成功返回的特殊情況代碼。 – 2010-06-14 12:51:16

+0

啊,我不知道。好的,謝謝你! =] – Carl 2010-06-14 20:46:04

0

首先打破呼叫到更清晰的邏輯:

int nRet = WSASend(m_socket, socketData->SetBuffer(socketData->GenerateLoginRequestHeader()), 1, NULL, NULL, reinterpret_cast<OVERLAPPED*>(socketData), NULL); 
if (nRet == SOCKET_ERROR) 
{ 
    if ((WSAGetLastError()) == WSA_IO_PENDING) 
     nRet = 0; // ok 
    else 
     throw std::exception("Failed to send data."); // failed 
} 

此外,你可以在我的代碼看,你應該根據自己WSASend無法通過「& bytesSent」參數:

如果 lpOverlapped參數不爲NULL,則爲該參數使用NULL,以避免可能的錯誤結果 。

除此之外,您對WSASend()的調用看起來不錯。

+0

好的,我會改變它。謝謝! – Carl 2010-06-14 10:43:36