【问题标题】:IOCP and overwritten bufferIOCP 和覆盖缓冲区
【发布时间】:2012-07-27 13:59:15
【问题描述】:

我制作了一个 IOCP 来处理客户端连接,其中包含以下详细信息:

 - Threads = (CPU cores * 2)
 - Assigning an completion port to each socket
 - Accessing the socket context by Client Index or overlapped struct (either way is the same)

所以我正在尝试调试传入的数据包,它的工作原理就像一个魅力,除了一点但令人讨厌的细节......我在 WorkersThread 函数上设置了一个断点(我在哪里接收数据包)我正在观察缓冲区我接收的数据包,突然缓冲区被我从客户端获得的新数据包覆盖。

这是为什么呢?根据我读到的内容,IOCP 应该等到我处理数据包,在接收任何其他数据包之前向客户端发送响应。所以我在我的套接字上下文中设置了一个名为“处理”的标志,并且仍然得到了带有传入数据包的覆盖缓冲区。所以它根本不让我调试,这让我发疯了

是 ollydbg(调试器)故障导致其他线程在我设置断点时运行吗?还是我的 IOCP 实现中出现了一些错误?

这是我的 WorkerThread 的编码方式:

DWORD WINAPI WorkerThread(void* argument)
{
    int BytesTransfer;
    int BytesRecv;
    int ClientID;
    int result;
    OVERLAPPED* overlapped = 0;
    ClientInfo* clientinfo = 0;
    WSABUF wsabuf;
    int flags;
    //Exit only when shutdown signal is recv
    while (WaitForSingleObject(IOCPBase::internaldata->sockcontext.ShutDownSignal, NULL) !=  WAIT_OBJECT_0)
    {
        flags = 0; BytesTransfer = 0; BytesRecv = 0; ClientID = 0; 
        //Get from queued list
        if (GetQueuedCompletionStatus(IOCPBase::internaldata->sockcontext.CompletionPort, (LPDWORD)&BytesTransfer, (PULONG_PTR)&ClientID, &overlapped, INFINITE) == TRUE)
        {
            if (overlapped == 0)
            {
                //Fatal error
                break;
            }
            clientinfo = (ClientInfo*)overlapped;
            if (BytesTransfer != 0)
            {
                //Assign the buffer pointer and buffer len to WSABUF local
                clientinfo->RecvContext.RecvBytes = BytesTransfer;
                wsabuf.buf = (char*)clientinfo->RecvContext.Buffer;
                wsabuf.len = clientinfo->RecvContext.Len;
                //Switch for OperationCode
                //switch (IOCPBase::internaldata->ClientContext[ClientID].OperationCode)
                switch (clientinfo->OperationCode)
                {
                case FD_READ:
                    // Check if we have send all data to the client from a previous send
                    if (clientinfo->SendContext.SendBytes < clientinfo->SendContext.TotalBytes)
                    {
                        clientinfo->OperationCode = FD_READ;             //We set FD_READ caused on the next send, there could still be bytes left to send
                        wsabuf.buf += clientinfo->SendContext.SendBytes; //The buffer position is + sended bytes
                        wsabuf.len = clientinfo->SendContext.TotalBytes - clientinfo->SendContext.SendBytes; //the buffer len is total - sended bytes
                        //Send the remain bytes
                        result = WSASend(clientinfo->sock, &wsabuf, 1, (LPDWORD)&BytesRecv, flags, &clientinfo->overlapped, NULL);
                        if (result == SOCKET_ERROR && (WSAGetLastError() != WSA_IO_PENDING))
                        {
                            CloseClient(ClientID);
                        }
                        clientinfo->SendContext.SendBytes += BytesRecv;
                    }
                    else
                    {
                        if (clientinfo->Processing == 0)
                        {
                            clientinfo->OperationCode = FD_WRITE; //If no more bytes left to send now we can set the operation code to write (in fact is read)
                            memset(clientinfo->RecvContext.Buffer, NULL, MAX_DATA_BUFFER_SIZE); //Clean the buffer for recv new data
                            //Recv data from our client
                            clientinfo->RecvContext.RecvBytes = WSARecv(clientinfo->sock, &wsabuf, 1, (LPDWORD)&BytesRecv, (LPDWORD)&flags, &clientinfo->overlapped, NULL);
                            if (clientinfo->RecvContext.RecvBytes == SOCKET_ERROR &&  WSAGetLastError() != WSA_IO_PENDING)
                            {
                                CloseClient(ClientID);
                                break;
                            }
                        }
                    }
                    break;
                case FD_WRITE:
                    //Send data to the RecvProtocol
                    clientinfo->Processing = 1;
                    IOCPBase::internaldata->callback.RecvProtocol(clientinfo->RecvContext.Buffer, clientinfo->RecvContext.Len, ClientID);
                    clientinfo->Processing = 0;
                default:
                    break;
                }
            }
        }
    }
    return false;
}

查看clientinfo->RecvContext.Buffer时出现问题。我正在观察数据包,几秒钟后,缓冲区被一个新数据包覆盖。

谢谢!

【问题讨论】:

  • 请注意,在FD_READ 的情况下,您在if 语句中有一个break 语句,这个break不会 中断循环,因为它在switch 内。您要么必须重新设计算法,要么使用例如goto.

标签: c++ iocp


【解决方案1】:

没关系,我通过将数据包复制到我用来分析数据包的函数的堆栈帧来解决调试问题,这样我就没有覆盖问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-22
    • 2014-12-28
    • 1970-01-01
    • 2011-04-19
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 2012-09-19
    相关资源
    最近更新 更多