Проблема с wsarecv при использовании с IOCP

Я новичок в IOCP и борюсь с этим последние несколько недель. Ниже я вставил некоторую основную часть своего кода, относящуюся к IOCP. Это может быть выполнено не идеально, так как я вырезал часть кода, чтобы упростить понимание. Я борюсь с получением данных. Что касается wsarecv в рабочем потоке, wsarecv возвращает код ошибки WSA_IO_PENDING, поэтому я вызываю WSAGetOverlappedResult, чтобы проверить завершение операции. Twist появляется здесь, скорее он продолжается и вызывает мою локальную функцию ProcessTelegramData после WSAGetOverlappedResult , та же часть кода (wsarecv вызывается снова) снова выполняется другим рабочим потоком, который пытается вызвать ProcessTelegramData, и значение буфера в нем недействительно. Я не могу понять, почему другой поток снова вызывает wsarecv при вызове WSAGetOverlappedResult и почему значение буфера становится недействительным?

unsigned LicTCPServer::WorkerThread(LPVOID lpParam)
{
    //int nThreadNo = (int)lpParam;
    LicTCPServer* pThis = reinterpret_cast<LicTCPServer*>(lpParam);
    void *lpContext = NULL;
    OVERLAPPED       *pOverlapped = NULL;
    CClientContext   *pClientContext = NULL;
    DWORD            dwBytesTransfered = 0;
    int nBytesRecv = 0;
    int nBytesSent = 0;
    DWORD             dwBytes = 0, dwFlags = 0;

    //Worker thread will be around to process requests, until a Shutdown event is not Signaled.
    while (WAIT_OBJECT_0 != WaitForSingleObject(g_hShutdownEvent, 0))
    {
        BOOL bReturn = GetQueuedCompletionStatus(
            g_hIOCompletionPort,
            &dwBytesTransfered,
            (LPDWORD)&lpContext,
            &pOverlapped,
            INFINITE);


        if (NULL == lpContext)
        {
            //We are shutting down
            break;
        }

        //Get the client context
        pClientContext = (CClientContext *)lpContext;

        if ((FALSE == bReturn) /*|| ((TRUE == bReturn) && (0 == dwBytesTransfered))*/)
        {
            //Client connection gone, remove it.
            pThis->RemoveFromClientListAndFreeMemory(pClientContext);
            continue;
        }

        WSABUF *p_wbuf = pClientContext->GetWSABUFPtr();
        OVERLAPPED *p_ol = pClientContext->GetOVERLAPPEDPtr();
        //printf("reached %d\n",pClientContext->GetOpCode());
        printf("Get Queued received\n");

        switch (pClientContext->GetOpCode())
        {
        case OP_READ:
            {

                //Once the data is successfully received, we will print it.
                //pClientContext->SetOpCode(OP_WRITE);
                pClientContext->ResetWSABUF();

                dwFlags = 0;
                //int a = recv(pClientContext->GetSocket(), p_wbuf->buf, p_wbuf->len, 0);
                //Get the data.

                if(WSARecv(pClientContext->GetSocket(), p_wbuf, 1, &dwBytes, &dwFlags, p_ol, NULL) == SOCKET_ERROR)
                {
                    if (WSAGetLastError() != WSA_IO_PENDING)
                    {
                        printf("Error occured at WSARecv()\n");
                        return 0;
                    }

                }
                DWORD byteTr = 0;

                WSAGetOverlappedResult(pClientContext->GetSocket(),p_ol,&byteTr,TRUE,&dwFlags);

                if( byteTr > 0 )
                {
                    //doing some operatin on data received
                    printf("Process tele called\n");
                    g_pLicServFunc->ProcessTelegramData(pClientContext->GetSocket(), p_wbuf->buf, byteTr);
                }

                if ((SOCKET_ERROR == nBytesRecv) && (WSA_IO_PENDING != WSAGetLastError()))
                {
                    //WriteToConsole("\nThread %d: Error occurred while executing WSARecv().", nThreadNo);

                    //Let's not work with this client
                    //TBC
                    //RemoveFromClientListAndFreeMemory(pClientContext);
                }
            }

            break;

        case OP_WRITE:

            char szBuffer[MAX_BUFFER_LEN];
            //Send the message back to the client.
            pClientContext->SetOpCode(OP_READ);


            pClientContext->SetTotalBytes(dwBytesTransfered);
            pClientContext->SetSentBytes(0);

            //p_wbuf->len  = dwBytesTransfered;

            dwFlags = 0;
            DWORD temp;
            //Overlapped send
            printf("reached Going to send\n");
            //send(pClientContext->GetSocket(), p_wbuf->buf,p_wbuf->len, 0); 
            nBytesSent = WSASend(pClientContext->GetSocket(), p_wbuf, 1, 
                &temp, dwFlags, p_ol, NULL);

            if ((SOCKET_ERROR == nBytesSent) && (WSA_IO_PENDING != WSAGetLastError()))
            {
                //WriteToConsole("\nThread %d: Error occurred while executing WSASend().", nThreadNo);

                //Let's not work with this client
                //TBC
                //RemoveFromClientListAndFreeMemory(pClientContext);
            }

            break;

        default:
            printf("reached to default\n");
            //We should never be reaching here, under normal circumstances.
            break;
        } // switch
    } // while

    return 0;
}

person Nipun    schedule 07.09.2011    source источник


Ответы (1)


У меня была аналогичная проблема с WSARecv, когда он всегда ставился в очередь на завершение ввода-вывода, даже если он сразу же завершался успешно. Мне пришлось игнорировать возвращаемое значение, указывающее на успех, и вместо этого обрабатывать поставленный в очередь результат, полученный от GetQueuedCompletionStatus.

person Scott Conger    schedule 05.06.2012