Once I've created my completion port and associated my device with it (a socket in this case), do I need to call WSARecv() to have it actually start detecting messages?
I need to use a completion port to detect if there is data to be read on multiple sockets and handle each one according (like select).
STEP1 CREATE THE COMPLETION PORT:
HANDLE hIocp;
hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
NULL,(ULONG_PTR)0, 0);
if (hIocp == NULL) {
// Error
}
STEP2 CREATE SOCKET(S) AND ASSOCIATE WITH IOCP:
SOCKET s;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
// Error
}
if (CreateIoCompletionPort((HANDLE)s, hIocp, (ULONG_PTR)0, 0) == NULL) {
// Error
}
Quote
At this point, the socket s is associated with the completion port. Any overlapped operations performed on the socket will use the completion port for notification. Note that the third parameter of CreateIoCompletionPort allows a completion key to be specified along with the socket handle to be associated.
NOTE: The Completion Key! It can be used to pass context information that is associated with the socket, like a struct for each connection containing extra information.
Now comes the fun part, polling! You need to create some threads to poll GetQueuedCompletionStatus. Typically one per processor works pretty good.
Quote
When an overlapped call is made, a pointer to an overlapped structure is passed as a parameter. GetQueuedCompletionStatus will return the same pointer when the operation completes. With this structure alone, however, an application can't tell which operation just completed. In order to keep track of the operations that have completed, it's useful to define your own OVERLAPPED structure that contains any extra information about each operation queued to the completion port (see Figure 1).
So you need to define your own OVERLAPPED structure, I usually call mine OVERLAPPEDEX. You specifically need to include a STATE variable, to know what kind of operation just occured (kinda like an enum?).
OVERLAPPEDEX STRUCT:
typedef struct OVERLAPPEDEX {
OVERLAPPED overlapped;
SOCKET s, c;
int state;
WSABUF buffer;
DWORD dwBytes, dwFlags;
// anything else useful can go here
};
#define ST_READ 0
#define ST_WRITE 1
#define ST_ACCEPT 2
WORKER THREAD/POLLER:
DWORD WINAPI WorkerThread(LPVOID lpParam)
{
ULONG_PTR *PerHandleKey;
OVERLAPPED *Overlapped;
OVERLAPPEDEX *OverlappedEx, *New*OverlappedEx;
DWORD dwBytesXfered;
while (1)
{
ret = GetQueuedCompletionStatus(hIocp,&dwBytesXfered,(PULONG_PTR)&PerHandleKey, &Overlapped, INFINITE);
if (ret == 0)
{
// Operation failed
continue;
}
OverlappedEx = CONTAINING_RECORD(Overlapped, OVERLAPPEDEX, overlapped);
switch (OverlappedEx->state)
{
case OP_ACCEPT:
// Client socket is contained in OverlappedEx.c
// Associate client socket with completion port
CreateIoCompletionPort((HANDLE)OverlappedEx->c,hIocp,(ULONG_PTR)0,0);
// Need a new OVERLAPPEDEX structure
// for the newly accepted socket.
NewOverlappedEx = AllocateOverlappedEx();
if (!NewOverlappedEx )
{
// Error
}
NewOverlappedEx->s = OverlappedEx->c;
NewOverlappedEx->state = OP_READ;
// This function prepares the data to be sent
PrepareSendBuffer(&NewOverlappedEx->buffer);
ret = WSASend(NewOverlappedEx->s,&NewOverlappedEx->buffer,1,&NewOverlappedEx->dwBytes,0,&NewOverlappedEx.overlapped,NULL);
if (ret == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
// Error
}
}
// Put structure in look aside list for later use
FreeOverlappedPlus(OverlapPlus);
// Signal accept thread to issue another AcceptEx
SetEvent(hAcceptThread);
break;
case OP_READ:
// ...
break;
} // switch
} // while
} // WorkerThread
enough for me, have fun ;P
Wow, way to post meaningless, redundant code, that I've already seen, and then not answer my question.
Quote from: Maddox on July 27, 2006, 12:32 PM
Wow, way to post meaningless, redundant code, that I've already seen, and then not answer my question.
I found that funny.
I didn't... I'm trying to figure out the same problem. :(
Quote from: Maddox on July 23, 2006, 09:56 AM
Once I've created my completion port and associated my device with it (a socket in this case), do I need to call WSARecv() to have it actually start detecting messages?
Iirc, yes, and then again every time you receive data.