为 posix recv 设置超时会导致 udp 数据包丢失吗?

Can setting a timeout for posix recv cause lost udp packets?

本文关键字:数据包 udp recv posix 设置 超时      更新时间:2023-10-16

我找到了关于如何为 posix 套接字设置超时的答案。该答案的 linux 部分:

// LINUX
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

以及 POSIX 文档中的引用:

SO_RCVTIMEO

设置超时值,该值指定输入函数在完成之前等待的最长时间。它接受一个时间值 具有秒数和微秒数的结构,指定 限制等待输入操作完成的时间。如果 接收操作已阻止了很长时间而没有接收 其他数据,它应返回部分计数或 errno 设置为 [EAGAIN] 或 [EWILLBLOCK] 如果未收到数据。此的默认值 选项为零,表示接收操作不应 超时。此选项采用时间值结构。请注意,并非全部 实现允许设置此选项。

我不明白的是:这会导致丢失 udp 包吗? 如果在收到 udp 包时达到超时怎么办?

还相关:设置 UDP 套接字的接收 fcn 超时

PS:我知道UDP本质上是不可靠的,所以我的问题实际上主要是关于处理udp消息时发生超时的情况。

否;它不会让你更有可能丢弃数据包。

查看网络传输如何在较低级别发生;您有一个网卡。 当此卡接收数据时,无论您的程序在做什么,它都会将数据存储到它自己的内存区域中。 当您调用 recv 时;您要求操作系统将数据从网卡内存移动到程序内存。 这意味着,如果您的线程正在执行其他操作时,数据包传入;它不仅会被丢弃,还会在下次线程获取数据时进行处理。

如果您的线程调用 recv 的频率不够高;那么网卡的内存将变满。 发生这种情况时,无法存储新数据包;如果它使用TCP,那么路由器将被告知它无法处理它;如果是UDP,那么它将被简单地丢弃。 正是这部分使UDP本质上不可靠,因为它可能在数据包传输过程中的任何时候发生。

超时会影响线程等待数据出现在网卡内存区域中的时间;除非您不再调用 recv;否则不会影响丢弃的数据包。

答案是否定的,丢失UDP数据将违反POSIX:

recv() 函数应返回写入缓冲区参数指向的缓冲区的消息长度。对于基于消息的套接字(如 SOCK_DGRAM 和 SOCK_SEQPACKET),应在单个操作中读取整个消息

据推测,"部分计数"仅在使用MSG_WAITALL选项时发生的是基于连接的套接字。

话虽如此,SO_RECVTIMEO的使用通常是不受欢迎的,在套接字上实现超时的"正确"方法是使用非阻塞套接字和select()。这是出于历史原因,而不是因为设置超时本质上是糟糕的设计或其他什么。如果您坚持使用SO_RECVTIMEO,请注意潜在的可移植性问题:

  • POSIX提到了SO_RECVTIMEO,但并不要求
  • 在 Windows 上,rcv() 中的超时会使套接字处于错误状态,您应该立即关闭它。在 POSIX 上,您可以(根据我的经验)在SO_RECVTIMEO引起的超时后仍然使用套接字,但有人可能会争辩说,规范并不能 100% 保证
  • 这一点