Возможно ли не получить завершение для вызова WSASend? - PullRequest
2 голосов
/ 30 марта 2011

Как видно из заголовка, возможно ли для успешного WSASend вызова на сокете, связанном с портом завершения ввода / вывода, не публиковать завершение по любой причине, кроме окончания потока?

У меня странная ситуация, когда кажется, что завершение не публикуется для WSASend, что приводит к утечке сокета;приложение думает, что отправка все еще ожидает сокета и отказывается освободить его.

Код отправки выглядит следующим образом:

void CSocketServer::Write(
    Socket *pSocket,
    CIOBuffer *pBuffer) const
{
    pSocket->AddRef();

    pBuffer->SetOperation(IO_Write_Completed);
    pBuffer->SetupWrite();
    pBuffer->AddRef();

    DWORD dwFlags = 0;
    DWORD dwSendNumBytes = 0;

    if (SOCKET_ERROR == ::WSASend(
        pSocket->m_socket,
        pBuffer->GetWSABUF(), 
        1, 
        &dwSendNumBytes,
        dwFlags,
        pBuffer, 
        NULL))
    {
        DWORD lastError = ::WSAGetLastError();

        if (ERROR_IO_PENDING != lastError)
        {
            pSocket->OnConnectionError(WriteError, pBuffer, lastError);

            pSocket->WriteCompleted();  // this pending write will never complete...

            pSocket->Release();
            pBuffer->Release();
        }
    }
    // Note: even if WSASend returns SUCCESS an IO Completion Packet is 
    // queued to the IOCP the same as if ERROR_IO_PENDING was returned.
    // Thus we need no special handling for the non error return case.
    // See http://support.microsoft.com/default.aspx?scid=kb;en-us;Q192800
    // for details.
}

Ответы [ 2 ]

2 голосов
/ 31 марта 2011

Используете ли вы какие-нибудь необычные функции, такие как отключение завершений для успешных вызовов с помощью FILE_SKIP_COMPLETION_PORT_ON_SUCCESS?

Используете ли вы какую-либо форму управления потоком на своих отправках или вы просто отправляете, когда захотите и так часто, как хотите? То, что вы МОЖЕТЕ увидеть, является просто МЕДЛЕННЫМ завершением, потому что стек TCP контролирует перегрузку и еще не может отправить ваши данные. Если вы продолжаете отправлять данные неконтролируемым образом, вы часто можете попасть в ситуацию, когда выполнение завершается все дольше и дольше. Особенно, если вы отправляете данные с более высокой скоростью, чем соединение TCP успешно передает на другую сторону, и особенно если окно TCP не такое большое. Смотрите здесь: http://www.lenholgate.com/blog/2008/07/write-completion-flow-control.html для получения дополнительной информации.

Конечно, это может быть просто ошибка в логике отправки. Не могли бы вы опубликовать какой-нибудь код?

Обратите внимание, что существует известная ошибка с WSARecv () и UDP (поэтому не имеет никакого отношения к вашему вопросу) при использовании FILE_SKIP_COMPLETION_PORT_ON_SUCCESS, которая дает ситуацию, которую вы описываете, если датаграмма больше, чем предоставленный вами буфер и вызов WSARecv() сгенерировал бы WSAEMOREDATA; смотрите здесь: http://www.lenholgate.com/blog/2010/01/file-skip-completion-port-on-success-and-datagram-socket-read-errors.html

1 голос
/ 31 марта 2011

Можно предотвратить публикацию порта завершения, установив младший бит действительной структуры OVERLAPPED hEvent:

Из документации по GetQueuedCompletionStatus:

Даже если вы прошли функцию дескриптор файла, связанный с порт завершения и действительный ПЕРЕКРЫТ структура, приложение может предотвратить уведомление о завершении порта. Это сделано путем указания действительного события ручка для члена hEvent ПЕРЕКРЫТЫЙ СТРУКТУРА, и настройка его младший бит. Действительный дескриптор события чей младший бит установлен, вводит / выводит завершение из очереди в порт завершения.

...