Winsock2 - 如何使用 MSG_WAITALL 打开允许 recv() 的 TCP 套接字?
Posted
技术标签:
【中文标题】Winsock2 - 如何使用 MSG_WAITALL 打开允许 recv() 的 TCP 套接字?【英文标题】:Winsock2 - how to open a TCP socket that allows recv() with MSG_WAITALL? 【发布时间】:2012-08-26 05:07:03 【问题描述】:在这段代码中:
// error checking is omitted
// init Winsock2
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
// connect to server
struct addrinfo *res = NULL, *ptr = NULL, hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
getaddrinfo(server_ip, "9999", &hints, &res);
SOCKET client_socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
connect(client_socket, res->ai_addr, (int)res->ai_addrlen);
freeaddrinfo(res);
res = NULL;
// read the data
unsinged int size1;
if (recv(client_socket, (char*)&size1, sizeof(int), MSG_WAITALL) == SOCKET_ERROR)
return WSAGetLastError();
(注意recv()
中的MSG_WAITALL
标志)一切正常,期待recv()
。 WSAGetLastError()
返回WSAEOPNOTSUPP
。
MSDN 声明
请注意,如果底层传输不支持 MSG_WAITALL,或者如果套接字处于非阻塞模式,则此调用将失败并显示 WSAEOPNOTSUPP。此外,如果 MSG_WAITALL 与 MSG_OOB、MSG_PEEK 或 MSG_PARTIAL 一起指定,则此调用将失败并显示 WSAEOPNOTSUPP。数据报套接字或面向消息的套接字不支持此标志。
但看起来我并没有从这个列表中做某事。为什么我的recv()
呼叫不起作用?
【问题讨论】:
【参考方案1】:看起来我并没有从这个列表中做某事。
是的,您是列表中的第一项:
底层传输不支持 MSG_WAITALL
Microsoft 的默认 TCP 传输提供程序不支持 MSG_WAITALL
。 recv()
和一般的 Winsock 不仅限于 Microsoft 的 TCP 提供程序。它支持第 3 方提供商,以及提供商支持的任何传输协议 - TCP、UDP、IPX、ICMP、RAW 等。
在使用微软的 TCP 时,如果你想让recv()
等到所有请求的 TCP 数据都接收完,你必须将 socket 设置为阻塞模式(它的默认模式),然后设置flags
的参数recv()
为 0。但即使这样也不能保证,recv()
可以返回比请求更少的字节,因此您应该准备好循环调用 recv()
,直到实际接收到所有预期的字节。
【讨论】:
我知道这是一个非常古老的答案,但它仍然不正确。 MSG_WAITALL 并不意味着底层协议需要支持任何类型的消息概念。 WinSock2 TCP 套接字支持 MSG_WAITALL。 @BluBb_mADe Microsoft 的默认传输提供程序不支持MSG_WAITALL
,但 Winsock2 不仅限于该提供程序。其他第 3 方传输提供商可能支持MSG_WAITALL
。这就是为什么引用的文件是这样写的——它是一份合同,而不是一份保证。 “IF 底层传输......”我已经更新了我的答案。
我真的很想看到这个声称默认 TCP 不支持 MSG_WAITALL 的来源,因为我一直在使用socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
,这可以说是使用不支持 ipv6 的最默认方式与recv(..., MSG_WAITALL)
结合使用多年没有错误或问题。以上是关于Winsock2 - 如何使用 MSG_WAITALL 打开允许 recv() 的 TCP 套接字?的主要内容,如果未能解决你的问题,请参考以下文章
bind(...) 总是使用 WinSock2 返回 -1 -- C++