- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试将 GetQueuedCompletionStatus 与 Winsocks 一起使用,但我似乎无法正确执行。流程如下:
void foo() {
...
SOCKET sck = WSASocket(AF_INET, SOCK_DGRAM, 0,
NULL, 0, WSA_FLAG_OVERLAPPED);
....
bind(sck,(struct sockaddr *)&addr,sizeof(struct sockaddr_in));
HANDLE hPort = CreateIoCompletionPort((HANDLE)sck, NULL, 0, 0 );
OVERLAPPED pOverlapped = {0,};
WSARecvFrom(sck,NULL,0,NULL,NULL,(struct sockaddr *)&laddr,&lsize,&pOverlapped,0);
BOOL bReturn = GetQueuedCompletionStatus(
hPort,
&rbytes,
(LPDWORD)&lpContext,
&pOutOverlapped,
INFINITE);
...
}
然后,我从外部工具将一些网络数据发送到绑定(bind)端口。 GetQueuedCompletionStatus 返回 FALSE,GetLastError() 返回 ERROR_MORE_DATA,这听起来是正确的,因为我没有在 WSARecvFrom 中提供缓冲区。
问题是如何提供缓冲区来实际从失败的 I/O 操作中获取数据?
我尝试使用原始重叠结构发出 WSARecvFrom,但它只是将另一个读取排队,并且在发送更多网络数据之前对 GetQueuedCompletionStatus 的后续调用不会返回。
在没有重叠结构的情况下调用 WSARecvFrom 会阻止它,并且在发送更多网络数据之前它也不会返回。
那么,如何正确处理 ERROR_MORE_DATA,而不丢失第一次操作的数据?
最佳答案
您必须为 WSARecvFrom()
提供一个缓冲区,就像任何读取操作一样,无论您是否使用 IOCP。您必须确保缓冲区在内存中保持有效,直到 IOCP 操作完成。 IOCP 填充您提供的缓冲区,然后在完成时通知完成端口。
UDP 无法在单个数据报中传输超过 65535 字节,因此您可以将其用作最大缓冲区大小。
在您的示例中,您的代码被编写为同步运行(完全违背了使用 IOCP 的目的),因此您可以使用本地缓冲区:
void foo() {
...
SOCKET sck = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (sck == INVALID_SOCKET)
{
// error, do something...
return;
}
....
bind(sck,(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
HANDLE hPort = CreateIoCompletionPort((HANDLE)sck, NULL, 0, 0 );
if (!hPort)
{
// error, do something...
return;
}
WSAOVERLAPPED Overlapped = {0};
Overlapped.hEvent = WSACreateEvent();
BYTE buffer[0xFFFF];
DWORD dwBytesRecvd = 0;
DWORD dwFlags = 0;
sockaddr_in fromaddr = {0};
int fromaddrlen = sizeof(fromaddr);
WSABUF buf;
buf.len = sizeof(buffer);
buf.buf = buffer;
int iRet = WSARecvFrom(sck, &buf, 1, &dwBytesRecvd, &dwFlags, (sockaddr*)&fromaddr, &fromaddrlen, &Overlapped, NULL);
if (iRet == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
// error, do something...
return;
}
DWORD rBytes;
ULONG_PTR key;
LPOVERLAPPED pOverlapped = NULL;
if (!GetQueuedCompletionStatus(hPort, &rbytes, &key, &pOverlapped, INFINITE))
{
if (pOverlapped)
{
// WSARecvFrom() failed...
}
else
{
// GetQueuedCompletionStatus() failed...
}
// do something...
return;
}
}
// I/O complete, use buffer, dwBytesRecvd, dwFlags, and fromaddr as needed...
}
但是,这违背了 IOCP 的目的。如果您确实想要同步,则可以使用 recvfrom()
来代替,并让它阻塞调用线程,直到数据到达。当有一个线程池为完成端口提供服务时,IOCP 效果最佳。调用 WSARecvFrom()
并让它在后台工作,不要等待它。让一个单独的线程调用GetQueuedCompletionPort()
并在收到数据时处理数据,例如:
struct MyOverlapped
{
WSAOVERLAPPED overlapped;
BYTE buffer[0xFFFF];
DWORD buflen;
DWORD flags;
sockaddr_storage fromaddr;
int fromaddrLen;
};
HANDLE hPort = NULL;
void foo() {
...
SOCKET sck = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (sck == INVALID_SOCKET)
{
// error, do something...
return;
}
....
bind(sck,(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
hPort = CreateIoCompletionPort((HANDLE)sck, NULL, 0, 0 );
if (!hPort)
{
// error, do something...
return;
}
MyOverlapped *ov = new MyOverlapped;
ZeroMemory(ov, sizeof(*ov));
ov->overlapped.hEvent = WSACreateEvent();
ov->fromaddrlen = sizeof(ov->fromaddr);
WSABUF buf;
buf.len = sizeof(ov->buffer);
buf.buf = ov->buffer;
int iRet = WSARecvFrom(sck, &buf, 1, &ov->buflen, &ov->flags, (sockaddr*)&ov->fromaddr, &ov->fromaddrlen, (WSAOVERLAPPED*)ov, NULL);
if (iRet == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
// error, do something...
return;
}
// WSARecvFrom() is now operating in the background,
// the IOCP port will be signaled when finished...
}
else
{
// data is already available,
// the IOCP port will be signaled immediately...
}
...
}
...
// in another thread...
{
...
DWORD rbytes;
ULONG_PTR key;
MyOverlapped *ov = NULL;
if (!GetQueuedCompletionStatus(hPort, &rbytes, &key, (LPOVERLAPPED*)&ov, INFINITE))
{
if (ov)
{
// WSARecvFrom() failed...
// free ov, or reuse it for another operation...
}
else
{
// GetQueuedCompletionStatus() failed...
}
}
else
{
// use ov as needed...
// free ov, or reuse it for another operation...
}
...
}
关于使用 GetQueuedCompletionStatus 和 ERROR_MORE_DATA 的套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31883438/
我正在编写一个服务器应用程序,我想使用 IOCompletion 端口,所以我为服务器编写了一个原型(prototype),但我遇到了 GetQueuedCompletionStatus 的问题,它永
IOCP 服务器使用 WebSocket 连接。当浏览器发送关闭帧时,服务器删除这个客户端,closesocket函数调用客户端的对象析构函数。但即使在套接字关闭后,GetQueuedCompleti
我编写了基于 iocp 机制管理网络通信的复杂库。问题是,当服务器通过调用 API 方法 closesocket() 关闭连接时,此信息有时会延迟几秒甚至几分钟传输到客户端。我用于检测连接关闭的代码如
我有一个通过串行端口生成消息的设备。当我重新启动设备时,IO 完成端口停止读取字节。 代码是调用 GetQueuedCompletionStatus(): BOOL bRet = GetQueuedC
我有手工制作的线程池。线程从完成端口读取并做一些其他事情。必须结束一个特定的线程。如果它卡在 GetQueuedCompletionStatus() 或 GetQueuedCompletionStat
GetQueuedCompletionStatus() 将完成通知从队列中取出,但它不会返回通知的类型(例如读取通知、写入通知)。 我有责任跟踪我发起的操作,例如,当我使用 WSARecv() 时,我
让我先概括一下。我通过三个端口接收数据。我有一个套接字、一个完成端口和一个工作线程。我调用 WSARecv,工作线程进程调用 GetQueuedCompletionStatus,然后是我的解析例程 R
我一直在测试将 IO 完成端口与线程池中的工作线程相结合,并偶然发现了一个我无法解释的行为。特别是,虽然下面的代码: int data; for (int i = 0; i (&data));
在程序终止期间,如何取消阻塞先前已通过调用 GetQueuedCompletionStatus() 阻塞的线程? 最佳答案 您可以使用 PostQueuedCompletionStatus API 调
我正在尝试将 GetQueuedCompletionStatus 与 Winsocks 一起使用,但我似乎无法正确执行。流程如下: void foo() { ... SOCKET sc
我正在尝试使用 Winsock 创建一个依赖于 IO 完成端口的 UDP 客户端/服务器类,但我无法让 GetQueuedCompletionStatus() 函数在新数据可用时返回。这可能是由于我的
正如它听起来的那样,我正在尝试异步 ReadDirectoryChangesW 和 IO 完成,但它不起作用,具体来说,GetLastError 重复返回 258 (GetQueuedCompleti
当调用 WSASend() 时,我必须向它传递一个 WSAOVERLAPPED 实例,并且我不能重新使用这个 WSAOVERLAPPED 实例,直到先前的 WSASend() 操作已经完成(即当一个完
有两个原因可以导致GetQueuedCompletionStatus()失败(返回FALSE),第一个是因为在调用时关闭了与其关联的完成端口句柄是突出的,如果 lpOverlapped 是 NULL,
背景:我正在使用 CreateIoCompletionPort、WSASend/Recv 和 GetQueuedCompletionStatus 在我的服务器上执行重叠套接字 io。对于流量控制,当发
切换到 Windows 8 后,我的应用程序停止工作。我花了几个小时调试问题,发现 IOCP 的行为在 Windows 8 和以前的版本之间有所不同。我提取了必要的代码来演示和重现问题。 SOCKET
我是一名优秀的程序员,十分优秀!