GetQueuedCompletionStatus-如何在没有任何套接字结构的情况下读取客户端消息
我正在尝试在Windows中使用C学习IOCP。其想法是拥有一个非阻塞服务器,该服务器具有处理客户端消息的线程 我现在知道如何接受客户了,等等 但我仍然不明白如何从GetQueuedCompletionStatus-如何在没有任何套接字结构的情况下读取客户端消息,c,windows,winsock2,iocp,C,Windows,Winsock2,Iocp,我正在尝试在Windows中使用C学习IOCP。其想法是拥有一个非阻塞服务器,该服务器具有处理客户端消息的线程 我现在知道如何接受客户了,等等 但我仍然不明白如何从GetQueuedCompletionStatus()读取并打印每个客户端的消息 我在网上看到,所有人都通过GetQueuedCompletionStatus()使用LPOVERLAPPED参数传递一个结构来引用它,但是如果没有任何结构,该怎么做呢 有人能告诉我这是否可行,并举一个小例子吗?您必须跟踪传递给WSARecv()等的缓冲区
GetQueuedCompletionStatus()
读取并打印每个客户端的消息
我在网上看到,所有人都通过GetQueuedCompletionStatus()
使用LPOVERLAPPED
参数传递一个结构来引用它,但是如果没有任何结构,该怎么做呢
有人能告诉我这是否可行,并举一个小例子吗?您必须跟踪传递给
WSARecv()
等的缓冲区。您可以通过将重叠的与每个缓冲区关联来实现这一点。当GetQueuedCompletionStatus()
告诉您哪个OVERLAPPED
已完成时,您就知道关联的缓冲区已准备就绪
这通常通过定义一个OVERLAPPED
作为其第一个成员的struct
来处理,因此指向OVERLAPPED
的指针也等于指向struct
的指针。然后,您可以在struct
中放入您想要的任何其他详细信息,如缓冲区、套接字等,以及您的应用程序处理数据所需的任何信息
例如:
enum IocpOp{opRead,opWrite};
类型定义结构
{
WSAOVERLAPPED ov;
IocpOp操作码;
插座sckt;
字节缓冲区[256];
德沃德缓冲区;
}MYIOCPINFO,*PMYIOCPINFO;
无效IoComplete(PMYIOCPINFO io,DWORD错误代码,DWORD numBytesTransferred)
{
如果(错误代码!=错误\u成功)
{
//根据需要处理故障。。。
免费(io);
返回;
}
开关(io->操作码)
{
案例阅读:
//根据需要使用io->buffer(缓冲区)至numBytesTransferred。。。
打破
案例opWrite:
如果(numBytesTransferrednumBytesInBuffer)
{
信息->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\u错误)
{
如果(WSAGetLastError()!=WSA\u IO\u挂起)
{
//根据需要处理故障。。。
免费(io);
}
}
返回;
}
打破
}
//在io->sckt上为下一个I/O操作重用io
//或免费io现在如果完成使用它。。。
免费(io);
}
}
...
PMYIOCPINFO io=malloc(sizeof(MYIOCPINFO));
如果(!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)=套接字错误)
{
如果(WSAGetLastError()!=WSA\u IO\u挂起)
IoComplete(io,WSAGetLastError(),0);
}
...
PMYIOCPINFO io=malloc(sizeof(MYIOCPINFO));
如果(!io)。。。
io->opCode=opWrite;
io->sckt=sckt;
//根据需要填充io->缓冲区。。。
io->numBytesInBuffer=。。。;
WSABUF buf;
buf.len=io->numBytesInBuffer;
buf.buf=(CHAR*)io->buffer;
if(WSASend(sckt,&buf,1,NULL,0,&(io->ov),NULL)=套接字错误)
{
如果(WSAGetLastError()!=WSA\u IO\u挂起)
IoComplete(io,WSAGetLastError(),0);
}
...
DWORD DWBYTESTTRANSFERRED=0;
ULONG_PTR ulCompletionKey=0;
LPOVERLAPPED LPOVERLAPPED=NULL;
if(GetQueuedCompletionStatus(hIOCP、&DWBYTESTTransfered、&ulCompletionKey、&lpOverlapped、INFINITE))
{
如果在CreateIOCompletionPort()中指定了(ulCompletionKey==MySocketIOCPKey)//则。。。
{
IoComplete((PMYIOCPINFO)lpOverlapped,ERROR\u SUCCESS,dwbytesttransfered);
}
其他的
{
...
}
}
其他的
{
如果(重叠)
{
//属于ulCompletionKey的I/O操作失败。。。
如果在CreateIOCompletionPort()中指定了(ulCompletionKey==MySocketIOCPKey)//则。。。
{
IoComplete((PMYIOCPINFO)lpOverlapped,GetLastError(),dwbytesttransferred);
}
其他的
{
...
}
}
其他的
{
//GetQueuedCompletionStatus()本身失败。。。
}
}
您必须跟踪传递给WSARecv()
等的缓冲区。您可以通过将重叠的与每个缓冲区关联来实现这一点。当GetQueuedCompletionStatus()
告诉您哪个OVERLAPPED
已完成时,您就知道关联的缓冲区已准备就绪
这通常通过定义一个OVERLAPPED
作为其第一个成员的struct
来处理,因此指向OVERLAPPED
的指针也等于指向struct
的指针。然后,您可以在struct
中放入您想要的任何其他详细信息,如缓冲区、套接字等,以及您的应用程序处理数据所需的任何信息
例如:
enum IocpOp{opRead,opWrite};
类型定义结构
{
WSAOVERLAPPED ov;
IocpOp操作码;
插座sckt;
字节缓冲区[256];
德沃德缓冲区;
}MYIOCPINFO,*PMYIOCPINFO;
无效IoComplete(PMYIOCPINFO io,DWORD错误代码,DWORD numBytesTransferred)
{
如果(错误代码!=错误\u成功)
{
//根据需要处理故障。。。
免费(io);
返回;
}
开关(io->操作码)
{
案例阅读:
//根据需要使用io->buffer(缓冲区)至numBytesTransferred。。。
打破
案例opWrite:
如果(numBytesTransferrednumBytesInBuffer)
{
信息->numBytesInBuffer-=numBytesTransferred;
memmove(io->buffer,io->buffer+numBytesTransferred,io->numBytesInBuffer);
WSABUF buf;
buf.len=io->numBytesInBuffer;