我尝试顺序读取 UDP 数据报。但在第二次读取操作期间出现问题。您可以在下面的代码片段中看到我第一次尝试读取并从 UDP 接收缓冲区丢失了 12 个字节的数据包。
Snippest Code:
sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
bytesInBuffer = 0;
if (-1 == ioctl(sock, FIONREAD, &bytesInBuffer))
{
printf("%s:%d, Fail to read bytes in buffer\n", __func__, __LINE__);
//If failure on ioctl then continue with select and read functionality
bytesInBuffer = 0;
}
printf("%s:%d, bytesInBuffer: %d\n", __func__, __LINE__, bytesInBuffer);
errno = 0;
/* Now recv as it will not block */
i32RetVal = recvfrom(sock, buffer, 40, MSG_NOSIGNAL | MSG_DONTWAIT, NULL, NULL);
printf("%s:%d, i32RetVal: %d\n", __func__, __LINE__, i32RetVal);
if (0 > i32RetVal)
{
printf("%s:%d, Recv failed with status: %d, Err: %d, SErr: %s\n", __func__, __LINE__, status, errno, strerror(errno));
status = -1;
break;
}
else if (0 == i32RetVal)
{
/* other side closed its send pipe */
status = -1;
printf("%s:%d, Recv failed as other side closed pipe\n", __func__, __LINE__);
break;
}
bytesInBuffer = 0;
if (-1 == ioctl(sock, FIONREAD, &bytesInBuffer))
{
printf("%s:%d, Fail to read bytes in buffer\n", __func__, __LINE__);
//If failure on ioctl then continue with select and read functionality
bytesInBuffer = 0;
}
printf("%s:%d, bytesInBuffer: %d\n", __func__, __LINE__, bytesInBuffer);
Output:
Recv_from:304, bytesInBuffer: 52
Recv_from:309, i32RetVal: 40
Recv_from:332, bytesInBuffer: 0
问题: 为什么读取缓冲区中的 12 个字节被丢弃?
任何帮助将不胜感激。 :)
最佳答案
你的代码是这样的:
- 查询接收缓冲区中下一个数据报的大小,为52字节
- 从接收缓冲区中的下一个数据报中读取 40 个字节并丢弃其余部分
- 检查
recvfrom
是否返回 0,这永远不会是这种情况,因为套接字未设置为非阻塞-- 我的错,忽略了MSG_DONTWAIT
标志 - 错误地假设零长度接收意味着“另一端已关闭连接”——这是针对 TCP 的。 UDP 没有连接或“管道”,没有什么可以关闭:零长度意味着“无有效载荷”数据报,它仅包含 header (这是完全合法的!)
- 查询接收缓冲区中下一个数据报的大小(为零,因为没有)
值得注意的是,UDP 在严格的每个数据报基础上工作。您无法读取半个数据报(好吧,您可以……但是……请继续阅读)。
无论发生什么,您总是会收到一个完整的数据报或什么也没有。数据报可能会丢失(将 丢失),但字节不会。您将也始终读取完整的数据报(“读取”与“消费”一样)。
读取数据报会将其从发送缓冲区中移除。读取半个数据报(或其任何部分)会将其从发送缓冲区中删除,丢弃其余部分。
关于c - 奇怪的UDP丢包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27229516/