Ошибка 6 в Overlapped WSARecv

153
24 апреля 2019, 05:40

Пишу новый сервер на IOCP. В потоке приёма новых подключений вызываю WSARecv (после успешного accept естественно). Срабатывает WSARecv с 3-5 попытки для клиента на C++, для браузера вообще ни разу не срабатывало (подключается по WebSocket). Причина всегда одна и та же - результат 6 после вызова WSAGetLastError().

Лог сервера выглядит примерно так (большие значения transferred не понятно откуда, актуальная информация в Received XX bytes from ... и Sent XX bytes to ...):

To stop server press ESC
Client 324 added (IP 127.0.0.1)
Recv error 6 on socket 324
Client 328 added (IP 127.0.0.1)
Recv error 6 on socket 328
Client 332 added (IP 127.0.0.1)
Recv error 6 on socket 332
Client 336 added (IP 127.0.0.1)
Thread 8 completed operation for client 336 (IP 127.0.0.1), transferred 62323228 bytes
Received 25 bytes from 336
Thread 7 completed operation for client 336 (IP 127.0.0.1), transferred 59963932 bytes
Sent 1 bytes to 336
Thread 8 completed operation for client 336 (IP 127.0.0.1), transferred 62323228 bytes
Received 11 bytes from 336
Thread 7 completed operation for client 336 (IP 127.0.0.1), transferred 59963932 bytes
Sent 1 bytes to 336
Thread 7 completed operation for client 336 (IP 127.0.0.1), transferred 59963932 bytes
Client 356 added (IP 127.0.0.1)
Thread 7 completed operation for client 356 (IP 127.0.0.1), transferred 59963932 bytes
Received 533 bytes from 356
Thread 8 completed operation for client 356 (IP 127.0.0.1), transferred 62323228 bytes
Sent 129 bytes to 356
Thread 8 completed operation for client 356 (IP 127.0.0.1), transferred 62323228 bytes
Client 360 added (IP 127.0.0.1)
Recv error 6 on socket 360
Client 364 added (IP 127.0.0.1)
Recv error 6 on socket 364
Client 368 added (IP 127.0.0.1)
Recv error 6 on socket 368
Client 372 added (IP 127.0.0.1)

Первые три попытки проводил один и тот же клиент. На четвёртый раз пошёл обмен. Последние неудачные попытки были от браузера - он вообще не смог подключиться.

Код принимающего потока:

unsigned int __stdcall AcceptThread(void * param){
    SOCKET ServerSocket = (SOCKET)param;
    WSANETWORKEVENTS WSAEvents;
    while(WAIT_OBJECT_0 != WaitForSingleObject(EventShutdown, 0)){
        if( WSA_WAIT_TIMEOUT != WSAWaitForMultipleEvents(1, &EventAccept, FALSE, 100, FALSE) ){
            WSAEnumNetworkEvents(ServerSocket, EventAccept, &WSAEvents);
            if((WSAEvents.lNetworkEvents & FD_ACCEPT) && (0 == WSAEvents.iErrorCode[FD_ACCEPT_BIT])){            
                client *Client = new client();
                int addrlen = sizeof(Client->address);
                //Accept remote connection attempt from the client
                if( INVALID_SOCKET == Client->Socket(accept(ServerSocket,(sockaddr*)&(Client->address),&addrlen)) ) delete Client;
                else if( NULL != CreateIoCompletionPort((HANDLE)Client->Socket(), hIOCP, (DWORD)Client, 0) ){
                    AddClient(Client);
                    DWORD flag = 0;
                    // Init receiving
                    int result = WSARecv(Client->Socket(), Client->RecvContext(), 1, Client->Rcvd(), &flag, Client->Overlapped(), NULL);
                    int err = WSAGetLastError();
                    if((SOCKET_ERROR == result) && (WSA_IO_PENDING != err)){
                        printf("Recv error %d on socket %d\n", err, Client->Socket());
                    }
                }
            }
        }
    }
    printf("AcceptThread closed\n");
    return 0;
}

С чем эта ошибка может быть связанна? Почему WSA_INVALID_HANDLE, и из-за какой магии это пропадает с n-ной попытки подключения?

PS: вся необходимая инициализация выполняется до создания потока с AcceptThread. Если бы не создался порт завершения или была ошибка при WSACreateEvent или WSAEventSelect на подготовленном принимающем сокете, до потока приёма дело бы не дошло.

Answer 1

Ох и Microsoft... Оказывается эта ошибка, WSA_INVALID_HANDLE, касается поля hEvent структуры OVERLAPPED.

Из MSDN

A handle to the event that will be set to a signaled state by the system when the operation has completed. The user must initialize this member either to zero or a valid event handle using the CreateEvent function before passing this structure to any overlapped functions

Я вот всегда, когда пишу свои структуры и классы, в их конструкторах инициализирую поля-указатели nullptr-ом. В WinAPI такие "мелочи" решили оставить на

user must

))

READ ALSO
Парсинг хэдэр файлов

Парсинг хэдэр файлов

Есть такая задача: пройтись по хэдэр файлу и записать в список все методы класса, определенные в хэдэре, при этом отделить чистые виртуальные,...

133
Зачем выделять память для переменных в стеке?

Зачем выделять память для переменных в стеке?

В теме еще разбираюсь плохо так что прошу строго не судить

174
Неправильный выбор конструктора

Неправильный выбор конструктора

Почему эта программа выводит doubledouble, я же явно указываю int?!

158
Обращение к структуре ProcessStartupInformation через wmi в C++

Обращение к структуре ProcessStartupInformation через wmi в C++

Пытаюсь разобраться с wmi, использую последний снипет из статьи Calling a Provider Method Не могу понять как указать ProcessStartupInformation для Win32_ProcessCreate на примере...

156