奇怪的UDP丢包

时间:2014-12-01 13:28:52

标签: c linux sockets udp recv

我尝试按顺序读取UDP数据。但在第二次阅读操作期间遇到问题。您可以在下面的snippest中看到我第一次尝试读取并从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个字节被丢弃了?

任何帮助将不胜感激。 :)

3 个答案:

答案 0 :(得分:3)

如果您阅读the UDP(7) manual page,您会看到FIONBIO的此条目:

  

...以整数形式返回 下一个待处理数据报 的大小(以字节为单位),或者当没有数据报待处理时返回0。 ...

(强调我的。)

因此FIONBIO没有给出缓冲区中的字节数,而是下一个数据包的大小。如果没有收到新的数据包,你就会得到零。

答案 1 :(得分:3)

您的代码的作用是:

  • 查询接收缓冲区中下一个数据报的大小,即52字节
  • 从接收缓冲区中的下一个数据报中读取40个字节,然后丢弃其余数据
  • 检查recvfrom是否返回0,,因为套接字未设置为非阻塞,所以永远不会出现这种情况 - 我的错误,忽略了MSG_DONTWAIT标志< / LI>
  • 错误地假设零长度接收意味着“另一端已关闭连接” - 这是针对TCP的。 UDP没有连接或“管道”,没有什么可以关闭:零长度意味着“无有效载荷”数据报,它只包含标题(这是完全合法的!)
  • 查询接收缓冲区中下一个数据报的大小(为零,因为没有)

值得注意的是,UDP在严格的每个数据报的基础上工作。你不能阅读半个数据报(好吧,你可以......但......继续阅读)。

无论发生什么情况,您都会收到完整的数据报或什么都没有。数据报可能会丢失(丢失),但不会丢失。您将始终读取完整的数据报(“阅读”,如“消费”)。

读取数据报会将其从发送缓冲区中删除。读取半个数据报(或其任何部分)将其从发送缓冲区中删除,丢弃其余部分

答案 2 :(得分:1)

缓冲区保存数据报,而不仅仅是有效负载数据。