sakdkjkj jjsdjds
sakdkjkj jjsdjds

Reputation: 69

GetQueuedCompletionStatus - How to read clients messages without any socket struct

I'm trying to learn IOCP with C in Windows. The idea is to have a non-blocking server with threads that handle client messages.

I understand by now how to accept clients, etc.

But I still don't understand how to read each client's messages from GetQueuedCompletionStatus() and print them.

I see online that all people pass a struct to reference it with GetQueuedCompletionStatus() using the LPOVERLAPPED parameter, but how to do it without any struct?

Can someone tell me if that is possible, and show a little example?

Upvotes: 0

Views: 139

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597101

You have to keep track of the buffers you pass to WSARecv(), etc. You do that by associating an OVERLAPPED with each buffer. When GetQueuedCompletionStatus() tells you which OVERLAPPED is finished, you thus known the associated buffer is ready.

This is commonly handled by defining a struct with an OVERLAPPED as its first member, so that a pointer to the OVERLAPPED is also equal to a pointer to the struct. Then you can put whatever other details you want in the struct, like the buffer, socket, etc, whatever your app needs to process the data.

For example:

enum IocpOp { opRead, opWrite };

typedef struct
{
    WSAOVERLAPPED ov;
    IocpOp opCode;
    SOCKET sckt;
    BYTE buffer[256];
    DWORD numBytesInBuffer;
} MYIOCPINFO, *PMYIOCPINFO;

void IoComplete(PMYIOCPINFO io, DWORD errorCode, DWORD numBytesTransferred)
{
    if (errorCode != ERROR_SUCCESS)
    {
        // handle failure as needed ...
        free(io);
        return;
    }

    switch (io->opCode)
    {
        case opRead:
            // use io->buffer up to numBytesTransferred as needed ...
            break;

        case opWrite:
            if (numBytesTransferred < io->numBytesInBuffer)
            {
                info->numBytesInBuffer -= numBytesTransferred;
                memmove(io->buffer, io->buffer + numBytesTransferred, io->numBytesInBuffer);

                WSABUF buf;
                buf.len = io->numBytesInBuffer;
                buf.buf = (CHAR*) io->buffer;

                if (WSASend(io->sckt, &buf, 1, NULL, 0, &(io->ov), NULL) == SOCKET_ERROR)
                {
                    if (WSAGetLastError() != WSA_IO_PENDING)
                    {
                        // handle failure as needed ...
                        free(io);
                    }
                }

                return;
            }

            break;
        }

        // reuse io for the next I/O operation on io->sckt
        // or free io now if done using it ...
        free(io);
    }
}

...

PMYIOCPINFO io = malloc(sizeof(MYIOCPINFO));
if (!io) ...
io->opCode = opRead;
io->sckt = sckt;

WSABUF buf;
buf.len = sizeof(io->buffer);
buf.buf = (CHAR*) io->buffer;

DWORD dwFlags = 0;
if (WSARecv(sckt, &buf, 1, NULL, &dwFlags, &(io->ov), NULL) == SOCKET_ERROR)
{
    if (WSAGetLastError() != WSA_IO_PENDING)
        IoComplete(io, WSAGetLastError(), 0);
}

...

PMYIOCPINFO io = malloc(sizeof(MYIOCPINFO));
if (!io) ...
io->opCode = opWrite;
io->sckt = sckt;

// fill io->buffer as needed ...
io->numBytesInBuffer = ...;

WSABUF buf;
buf.len = io->numBytesInBuffer;
buf.buf = (CHAR*) io->buffer;

if (WSASend(sckt, &buf, 1, NULL, 0, &(io->ov), NULL) == SOCKET_ERROR)
{
    if (WSAGetLastError() != WSA_IO_PENDING)
        IoComplete(io, WSAGetLastError(), 0);
}

...

DWORD dwBytesTransferred = 0;
ULONG_PTR ulCompletionKey = 0;
LPOVERLAPPED lpOverlapped = NULL;

if (GetQueuedCompletionStatus(hIOCP, &dwBytesTransferred, &ulCompletionKey, &lpOverlapped, INFINITE))
{
    if (ulCompletionKey == MySocketIOCPKey) // specified in CreateIOCompletionPort()...
    {
        IoComplete((PMYIOCPINFO)lpOverlapped, ERROR_SUCCESS, dwBytesTransferred);
    }
    else
    {
        ...
    }
}
else
{
    if (lpOverlapped)
    {
        // I/O operation belonging to ulCompletionKey failed...

        if (ulCompletionKey == MySocketIOCPKey) // specified in CreateIOCompletionPort()...
        {
            IoComplete((PMYIOCPINFO)lpOverlapped, GetLastError(), dwBytesTransferred);
        }
        else
        {
            ...
        }
    }
    else
    {
        // GetQueuedCompletionStatus() itself failed...
    }
}

Upvotes: 2

Related Questions