您必须跟踪传递给WSARecv() 等的缓冲区。您可以通过将OVERLAPPED 与每个缓冲区相关联来做到这一点。当GetQueuedCompletionStatus() 告诉您哪个OVERLAPPED 已完成时,您因此知道相关的缓冲区已准备好。
这通常通过定义struct 和OVERLAPPED 作为其第一个成员来处理,因此指向OVERLAPPED 的指针也等于指向struct 的指针。然后,您可以在 struct 中添加您想要的任何其他详细信息,例如缓冲区、套接字等,无论您的应用需要什么来处理数据。
例如:
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...
}
}