多线程IOCP客户端问题

时间:2010-06-11 03:47:21

标签: client iocp

我正在编写一个使用IO完成端口的多线程客户端。

我创建并连接了设置了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不是将最后一个错误集返回给WSA_IO_PENDING而返回SOCKET_ERROR,而是立即返回。

我需要IO挂起,并且要在我的线程函数中处理它的完成,这也是我的工作线程。

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

}

我以前做过这个,但我不知道在这种情况下出了什么问题,我非常感谢帮助我解决这个问题的任何努力。

2 个答案:

答案 0 :(得分:2)

除非你这样做,否则这不是问题。

只要您没有调用SetFileCompletionNotificationModes()并将标志设置为在成功时跳过完成端口处理,那么即使WSARecv(或其他)返回SUCCESS,IO完成数据包也会排队到IOCP,就好像已返回ERROR_IO_PENDING。因此,对于非错误返回情况,您无需特殊处理。

有关详细信息,请参阅http://support.microsoft.com/default.aspx?scid=kb;en-us;Q192800

答案 1 :(得分: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传递“&amp; bytesSent”参数:

  

如果是,请对此参数使用NULL   lpOverlapped参数不是NULL   避免可能的错误结果。

除此之外,您对WSASend()的调用看起来还不错。