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_WAITALLrecv() 和一般的 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++

关于winsock2中的connect函数

winsock2:服务器端代码调用`accept()`后如何获取已连接客户端的ipv4/ipv6地址

包括 stdafx.h winsock2 重新定义错误

WINSOCK2 WSAAsyncSelect 已弃用问题

在winsock2中使用选择