GetQueuedCompletionStatus挂起

时间:2012-10-10 05:09:28

标签: winsock freeze iocp

我试着找出我的程序冻结的原因,并将其缩小到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;
            }
        }
    }

2 个答案:

答案 0 :(得分:2)

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

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

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

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

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

答案 1 :(得分:0)

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