简体   繁体   English

IO 完成端口返回 NULL 完成密钥

[英]IO Completion port returning NULL Completion Key

First time using IO Completion Ports.第一次使用 IO 完成端口。 I'm having an issue where the GetQueuedCompletionStatus returns a Null for the Completion Key, which I am using to pass a data struct with handles for other portions of the code.我遇到了一个问题, GetQueuedCompletionStatus返回一个 Null 作为完成密钥,我用它来传递一个带有代码其他部分句柄的数据结构。

The GetQueuedCompletionStatus seems to be triggering off messages received just fine otherwise. GetQueuedCompletionStatus似乎触发了收到的消息,否则就好了。

I tried to include just the code involving the IO Completion ports:我试图只包含涉及 IO 完成端口的代码:

The Data Structs:数据结构:

    typedef struct _THREAD_MESSAGE
{
    mutex cmd_mtx;
    string command;
} THREAD_MESSAGE, * LPTHREAD_MESSAGE;

typedef struct _LISTEN_SOCKET_DATA
{
    SOCKET Socket;
    int    Port;
    HANDLE hAcceptEvent;
    HANDLE IOCP;
    VOID* MessageProcessor;
    ConfigHandler* CfgHandle;
    // Other information useful to be associated with the handle
} LISTEN_SOCKET_DATA, * LPLISTEN_SOCKET_DATA;

typedef struct _CONNECTED_SOCKET_DATA
{
    SOCKET Socket;
    int Port;
    HANDLE IOCP;
    VOID* MessageProcessor;
    ConfigHandler* CfgHandle;
} CONNECTED_SOCKET_DATA, * LPCONNECTED_SOCKET_DATA;

#define OPERATION_TYPE_UNKNOWN      0
#define OPERATION_TYPE_SEND         1
#define OPERATION_TYPE_RECV         2
typedef struct
{
    OVERLAPPED* Overlapped;
    CHAR Buffer[DATA_BUFSIZE];
    int BufferLen;
    int OperationType;
    string PacketName;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;

The completion port was initialized with:完成端口初始化为:

m_CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

The Listener:聆听者:

//Thread for handling Listener sockets and Accepting connections
DWORD ListenThread(LPVOID lpParam)
{
    LPLISTEN_SOCKET_DATA pSocketData = (LPLISTEN_SOCKET_DATA)(lpParam);
    WSANETWORKEVENTS NetworkEvents;
    DWORD dwRet;
    SOCKADDR_IN NewSockAddr;
    SOCKET      NewSocket;
    int         nLen;

    while (true) //run forever
    {
        //Wait for event
        dwRet = WSAWaitForMultipleEvents(1,
            &(pSocketData->hAcceptEvent),
            false,
            100,
            false);

        //Nothing happened, back to top
        if (dwRet == WSA_WAIT_TIMEOUT)
            continue;

        //We got a event, find out which one.
        int nRet = WSAEnumNetworkEvents(pSocketData->Socket,
            pSocketData->hAcceptEvent,
            &NetworkEvents);
        if (nRet == SOCKET_ERROR)
        {
            wprintf(L"WSAEnumNetworkEvents error %ld\n", WSAGetLastError());
            break;
        }

        //We got a Accept event
        if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
        {
            //Check for errors
            if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] == 0)
            {
                
                // Accept new connection
                nLen = sizeof(SOCKADDR_IN);
                NewSocket = accept(pSocketData->Socket,
                    (LPSOCKADDR)&NewSockAddr,
                    &nLen);
                if (NewSocket == SOCKET_ERROR)
                {
                    wprintf(L"accept() error %ld\n", WSAGetLastError());
                    break;
                }

                wprintf(L"Accepted Connection %ld", NewSockAddr.sin_addr.S_un.S_addr);

                //Set new connection as TCP connection, No Delay
                const char chOpt = 1;
                int nErr = setsockopt(NewSocket, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char));
                if (nErr == -1)
                {
                    wprintf(L"setsockopt() error %ld\n", WSAGetLastError());
                    break;
                }


                LPCONNECTED_SOCKET_DATA ConnectedSocketData = new CONNECTED_SOCKET_DATA;

                ZeroMemory(ConnectedSocketData, sizeof(CONNECTED_SOCKET_DATA));

                ConnectedSocketData->Socket = NewSocket;
                ConnectedSocketData->Port = pSocketData->Port;
                ConnectedSocketData->IOCP = pSocketData->IOCP;
                ConnectedSocketData->CfgHandle = pSocketData->CfgHandle;
                ConnectedSocketData->MessageProcessor = pSocketData->MessageProcessor;

                //Add the new socket to the completion port, message from the socker will be queued up for proccessing by worker threads.
                if (CreateIoCompletionPort((HANDLE)NewSocket, pSocketData->IOCP, (DWORD)ConnectedSocketData, 0) == NULL)
                {
                    wprintf(L"CreateIOCompletionPort error %ld\n", WSAGetLastError());
                    delete ConnectedSocketData;
                    ConnectedSocketData = NULL;
                    closesocket(NewSocket);
                    break;
                }                

                //Set the PerIOData, will be used at completion time
                LPPER_IO_OPERATION_DATA PerIOOperationData = new PER_IO_OPERATION_DATA;
                PerIOOperationData->BufferLen = 0;
                PerIOOperationData->OperationType = OPERATION_TYPE_RECV;
                DWORD RecvBytes = 0;
                DWORD Flags = 0;
                WSABUF DataBuf;
                DataBuf.len = DATA_BUFSIZE;
                DataBuf.buf = PerIOOperationData->Buffer;
                PerIOOperationData->Overlapped = new OVERLAPPED;
                ZeroMemory(PerIOOperationData->Overlapped, sizeof(OVERLAPPED));

                //Kick off the first Recv request for the Socket, will be handled by the completion Queue.
                if (WSARecv(NewSocket, &DataBuf, 1, &RecvBytes, &Flags, (PerIOOperationData->Overlapped), NULL) == SOCKET_ERROR)
                {
                    wprintf(L"WSARecv error %ld\n", WSAGetLastError());
                    return 0;
                }
            }
            else
            {
                wprintf(L"Unknown network event error %ld\n", WSAGetLastError());
                break;
            }
        }
    }
}

The Worker Thread, it crashes when it tries to use ConnectedSocketData due to the struct being null:工作线程,由于结构为 null,它在尝试使用 ConnectedSocketData 时崩溃:

    // Worker thread, processes IOCP messages.
DWORD ServerWorkerThread(LPVOID lpParam)
{
    HANDLE CompletionPort = (HANDLE)lpParam;
    DWORD BytesTransferred = 0;
    OVERLAPPED* lpOverlapped = NULL;
    LPCONNECTED_SOCKET_DATA ConnectedSocketData = NULL;
    LPPER_IO_OPERATION_DATA PerIoData = NULL;
    DWORD Flags = 0;
    WSABUF DataBuf;
    DWORD RecvBytes = 0;
    int DestinationAddress = 0;

    while (TRUE)//run forever
    {
        //Check for new message
        if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (PULONG_PTR)&ConnectedSocketData, (LPOVERLAPPED*)&lpOverlapped, INFINITE) == 0)
        {
            DWORD Err = GetLastError();
            if (Err != WAIT_TIMEOUT)
            {
                printf("GetQueuedCompletionStatus() failed with error %d\n", Err);

                if (closesocket(ConnectedSocketData->Socket) == SOCKET_ERROR)
                {
                    printf("closesocket() failed with error %d\n", WSAGetLastError());
                    return 0;
                }

                GlobalFree(ConnectedSocketData);
            }
            continue;
        }

        // retrieve IO data
        PerIoData = CONTAINING_RECORD(lpOverlapped, PER_IO_OPERATION_DATA, Overlapped);

        vector<SiteData>::iterator SiteDataIterator;
        vector<InstrumentData>::iterator InstrumentDataIterator;

        for (SiteDataIterator = ConnectedSocketData->CfgHandle->SiteConnections.begin();
            SiteDataIterator != ConnectedSocketData->CfgHandle->SiteConnections.end();
            SiteDataIterator++)
        {
            if (SiteDataIterator->Port == ConnectedSocketData->Port)
            {
                break;
            }
        }

Any Ideas why the IOCP is not passing the Completion Key?任何想法为什么 IOCP 没有通过完成密钥?

Any Ideas why the IOCP is not passing the Completion Key?任何想法为什么 IOCP 没有通过完成密钥?

of course it passing back exactly what you pass to CreateIoCompletionPort and I/O in place pointer to OVERLAPPED当然,它准确地将您传递给CreateIoCompletionPort的内容和 I/O 就地指针传回给OVERLAPPED

but at first但起初

CreateIoCompletionPort((HANDLE)NewSocket, pSocketData->IOCP, (DWORD)ConnectedSocketData, 0)

is wrong - only low 32 bit of ConnectedSocketData is used here, must be错了——这里只使用了ConnectedSocketData的低 32 位,必须是

CreateIoCompletionPort((HANDLE)NewSocket, pSocketData->IOCP, (DWORD_PTR)ConnectedSocketData, 0)

then, your definition of PER_IO_OPERATION_DATA然后,您对PER_IO_OPERATION_DATA的定义

typedef struct
{
    OVERLAPPED* Overlapped;
    CHAR Buffer[DATA_BUFSIZE];
    int BufferLen;
    int OperationType;
    string PacketName;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;

is always and critical error.总是和严重的错误。 must be一定是

typedef struct
{
    OVERLAPPED Overlapped;
    CHAR Buffer[DATA_BUFSIZE];
    int BufferLen;
    int OperationType;
    string PacketName;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;

by Overlapped (when it defined as OVERLAPPED* Overlapped ) impossible take back address of PER_IO_OPERATION_DATA .通过Overlapped (当它定义为OVERLAPPED* Overlapped时)不可能收回PER_IO_OPERATION_DATA的地址。 but from &Overlapped (when it defined as OVERLAPPED Overlapped ) already possible.但是从&Overlapped (当它定义为OVERLAPPED Overlapped时)已经可能。

i be better do next definition我最好做下一个定义

struct PER_IO_OPERATION_DATA : public OVERLAPPED
{
    CHAR Buffer[DATA_BUFSIZE];
    int BufferLen;
    int OperationType;
    string PacketName;
};

and use并使用

WSARecv(NewSocket, &DataBuf, 1, &RecvBytes, &Flags, PerIOOperationData, NULL)

and

PerIoData = static_cast<PER_IO_OPERATION_DATA*>(lpOverlapped);

you wrong handle case when GetQueuedCompletionStatus return false - you leak PerIoData it this case.GetQueuedCompletionStatus返回 false 时,您错误地处理了案例 - 您在这种情况下泄漏PerIoData

this is only top errors in your code, related to your direct question这只是您的代码中的主要错误,与您的直接问题有关

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM