Проблема многопоточного клиента IOCP - PullRequest
0 голосов
/ 11 июня 2010

Я пишу многопоточный клиент, использующий порт завершения ввода-вывода.

Я создаю и подключаю сокет с установленным атрибутом 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.");
}

Я связываю порт завершения ввода-вывода с сокетом.

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.");
}

Вместо возврата SOCKET_ERROR с последней ошибкой, установленной в WSA_IO_PENDING, WSASend немедленно возвращается.

Мне нужно, чтобы IO ожидал и чтобы его завершение обрабатывалось в моей функции потока, которая также является моим рабочим потоком.

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

}

Я делал это раньше, но я не знаю, что происходит в этом случае, я был бы очень признателен за любые попытки помочь мне решить эту проблему.

Ответы [ 2 ]

2 голосов
/ 13 июня 2010

Это не проблема, если вы не сделаете это так.

Пока вы не вызываете SetFileCompletionNotificationModes () и устанавливаете флаг, чтобы пропустить завершение обработки порта в случае успеха, даже еслиWSARecv (или что-то еще) возвращает SUCCESS, пакет IO Completion помещается в очередь IOCP так же, как если бы ERROR_IO_PENDING был возвращен.Таким образом, вам не требуется специальная обработка для случая возврата без ошибок.

Подробнее см. http://support.microsoft.com/default.aspx?scid=kb;en-us;Q192800.

0 голосов
/ 14 июня 2010

Прежде всего разбейте вызов на более понятную логику:

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
}

Кроме того, как вы можете видеть в моем коде, вы НЕ должны передавать параметр "& bytesSent" в соответствии с WSASend :

Используйте NULL для этого параметра, если параметр lpOverlapped не равен NULL, чтобы избежать потенциально ошибочных результатов.

Кроме того, ваш вызов WSASend () выглядитхорошо.

...