2010-06-11 103 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