为 posix recv 设置超时会导致 udp 数据包丢失吗?
Can setting a timeout for posix recv cause lost udp packets?
我找到了关于如何为 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% 保证
这一点
- boost::asio UDP 广播客户端仅接收"fast"数据包
- 发送固定大小的 UDP 数据包
- 使用C++将UDP数据包存储在Structure中
- 在高数据包速率下最大限度地减少丢弃的 UDP 数据包 (Windows 10)
- Qt 在可预测的秒数后跳过 UDP 数据包
- 高频接收UDP数据包:丢包?
- C++ 通过 UDP 发送数据包,但不接收数据包
- 为 posix recv 设置超时会导致 udp 数据包丢失吗?
- 了解 UDP 数据包大小限制的 TCP 数据包大小限制以及它在 boost::asio 编程级别的含义
- 获取进入UDP数据包的目标端口
- 操纵Windows Explorer窗口时,UDP数据包会掉落
- 如何模拟QT UDP程序的数据包丢失
- C++ 使用 recvmmsg 丢弃 UDP 数据包
- 使用 UDP 协议从 Windows 套接字发送到 Qt 套接字的网络数据包上的结构编码和解码
- 如何在QT中接收适当的UDP数据包
- 使用ASIO捕获大量UDP数据包
- 如何正确接收多播UDP数据包
- C++ - 构造带有标头的数据包并通过 UDP 套接字发送
- 通过RecvFrom(UDP)接收数据包的一部分
- 服务器未收到UDP数据包,花费数小时试图找出问题所在