2

我试图找出我的程序冻结的原因,并将其范围缩小到 GetQueuedCompletionStatus()。

所有 IOCP 线程都被冻结,线程拥有的唯一阻塞调用是 GetQueuedCompletionStatus()。

即使仍有客户连接到相关的套接字,GetQueuedCompletionStatus() 是否有任何理由在大约 30 分钟~6 小时的运行时间后永远保持阻塞?

这是一个使用 IOCP 的 TCP Winsock 程序。操作系统是 Windows Server 2008 R2 Enterprise。

谢谢。

线程代码:

    while (TRUE)
    {
        pClient = NULL;
        pOverlapped = NULL;
        bRet = GetQueuedCompletionStatus(hCompletionPort, &dwIOLen, (LPDWORD)&pClient, (LPOVERLAPPED*)&pOverlapped, INFINITE);
        if (bRet == true && pClient != NULL && pOverlapped != NULL && pClient->bConnected == true && pClient->bToDisconnect == false)
        {
            if (pOverlapped->bIOMode == 0) // Recv
            {
                if (TryEnterCriticalSection(&pClient->mNetworkReadCSection))
                {
                    pClient->dwSockBuffLength += dwIOLen;

                    // Packet processing here...

                    WSABUF pWSABuf;
                    pWSABuf.buf = (char*)&pClient->mSockBuffer[pClient->dwSockBuffLength];
                    pWSABuf.len = 10000 - pClient->dwSockBuffLength;
                    DWORD dwRecvd;
                    DWORD dwFlags = 0;
                    memset(&pClient->mSockOverlapped, 0x00, sizeof(WSAOVERLAPPED));
                    pClient->mSockOverlapped.bIOMode = 0;
                    int iSent = WSARecv(pClient->ClientSocket, &pWSABuf, 1, &dwRecvd, &dwFlags, (WSAOVERLAPPED*)&pClient->mSockOverlapped, NULL);
                    if (iSent == SOCKET_ERROR)
                    {
                        if (WSAGetLastError() == 10053 || WSAGetLastError() == 10054 || WSAGetLastError() == 10058)
                        {
                            //pClient->bToDisconnect = true;
                            //LeaveCriticalSection(&pClient->mNetworkReadCSection);
                            OnDissconnect(pPacketWriter, pClient->iClientID);
                            continue;
                        }

                        if (WSAGetLastError() != 997 &&  WSAGetLastError() != 10004 && WSAGetLastError() != 10038)
                            WriteToFile("IOCPSocketErr.txt", "[%s] Socket Error: %d\n", pClient->szPlayerName, WSAGetLastError());
                    }

                    LeaveCriticalSection(&pClient->mNetworkReadCSection);
                }
                else
                {
                    PostQueuedCompletionStatus(hCompletionPort, dwIOLen, (DWORD)pClient, (OVERLAPPED*)pOverlapped);
                }
            }
            else if (pOverlapped->bIOMode == 1) // Send
            {
                dwBytesSent += dwIOLen;
            }
        }
    }
4

2 回答 2

2

这很可能是您的代码中的错误。

我与 IOCP 合作已经GetQueuedCompletionStatus()10 多年了,我从未在任何平台上看到过它的问题。

首先,断开连接上方的注释LeaveCriticalSection(&pClient->mNetworkReadCSection);将使您的套接字在此错误后锁定...

就个人而言,我更喜欢看到使用的错误常量而不是幻数,我很难确切地看到你在这里“处理”了哪些错误。

我希望您最终处于没有待处理的 I/O 操作的情况,因此您的 IOCP 线程上没有任何活动。您可以维护一个计数器用于调试目的,当您发出 I/O 操作时递增,完成时递减,当您将自己的完成发布到端口时也递增。这将帮助您查看当您闯入挂起的程序时是否有任何 I/O 操作挂起。请记住在发出操作之前增加计数器(如果操作失败,则减少它)而不是在之后发出它,否则如果完成发生在增量之前,计数器可能会变为负数。

于 2012-10-11T07:19:04.297 回答
0

如果我正确阅读了文档,您可能会遇到 GetQueuedCompletionStatus 返回 false 并且 pOverlapped 不为 NULL 的情况。也许您应该测试并处理这种情况。

于 2013-04-09T14:38:10.127 回答