c - WinSock2 的带有 MSG_WAITALL 标志的 recv 返回不完整的数据包,没有错误
问题描述
我WinSock2.h
用来从 TCP 套接字接收数据。这是创建套接字并从中接收的代码:
int Socket_Init(SOCKET * pSocket) {
struct addrinfo lHints;
struct addrinfo *lResult = nullptr;
memset(&lHints, 0, sizeof(lHints));
lHints.ai_family = AF_INET;
lHints.ai_socktype = SOCK_STREAM;
lHints.ai_protocol = IPPROTO_TCP;
if (getaddrinfo(ADDR, PORT_ID, &lHints, &lResult) != 0) {
return -1;
}
*pSocket = socket(lResult->ai_family, lResult->ai_socktype, lResult->ai_protocol);
if (*pSocket == INVALID_SOCKET) {
return -2;
}
// Set receive timeout.
uint32_t timeout = 10000;
if (setsockopt(*pSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) == SOCKET_ERROR) {
return -3;
}
// Set send timeout.
if (setsockopt(*pSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) == SOCKET_ERROR) {
return -4;
}
if (connect(*pSocket, lResult->ai_addr, (int)lResult->ai_addrlen) == SOCKET_ERROR) {
return -5;
}
return 0;
}
int Socket_Receive(char * buf, int len, SOCKET * pSocket) {
if (*pSocket == INVALID_SOCKET) {
return -1;
}
int nBytesReceived = recv(*pSocket, buf, len, MSG_WAITALL);
if (nBytesReceived == 0) {
return -2;
} else if (nBytesReceived == SOCKET_ERROR) {
if (WSAECONNABORTED == LAST_ERROR || WSAECONNRESET == LAST_ERROR) {
return -3;
} else {
return -4;
}
}
return nBytesReceived;
}
我使用此代码接收 131130 字节的数据包。使用 Wireshark,我可以看到在最后一个或倒数第二个分段数据包上重新传输时会发生不完整的数据包(堆栈将消息拆分为 1460 字节 + 标头的块)。发生这种情况时,recv()
返回 (131130 - size retransmitted) 而不是 131130。如果我再次读取丢失的字节数,我可以毫无问题地得到它们。
我的困惑来自于我正在使用该MSG_WAITALL
标志,这似乎并没有完全发挥作用。从文档中,recv()
只有在以下情况下MSG_WAITALL
才会返回标志:
- 调用者提供的缓冲区已满。
- 连接已关闭。
- 请求已被取消或发生错误。
但我没有收到错误,连接仍然打开,缓冲区未满。
我看到了这个线程,回复者说MSG_WAITALL
TCP 套接字不支持并使用 0 而不是MSG_WAITALL
. 我试过了,但这导致我的代码重试次数更多。此外,如果它不受支持,那么我相信该recv()
功能应该立即失败WSAEOPNOTSUPP
,但事实并非如此。
我错过了什么吗?
解决方案
推荐阅读
- android - 嵌入图像时,Zefyr 下方有很大的空间 - Flutter
- php - PHP 变量产生正确的字符串但抛出 JSON 错误
- boost - libboost1.74-dev 未在 Ubuntu 16.04 上安装
- android - 如何在 activity_main.xml 中添加子屏幕?
- java - 仅从具有多个过滤条件的数据库中获取选定的列 Spring Boot 2 JPA
- android - MPAndroidChart 堆积条形图显示错误/重复值
- python - 获取 Wireshark PacketList 窗口上 vScroll 向下箭头中间的 POINT
- javascript - 在 React Hook 中为用户类型设置 useState 到什么
- r - 错误 - 尝试查找不完整案例时
- c++ - 为什么重新定义字符串 str 不显示错误?