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

时间:2018-04-11 12:51:34

标签: c++ sockets posix

我找到this answer关于如何设置posix socket的超时。答案的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
     

设置超时值,该值指定输入函数在完成之前等待的最长时间。它接受时间   结构,以秒和微秒为单位指定   限制等待输入操作完成的时间。如果一个   接收操作在没有收到的情况下已经被阻止了这么多   附加数据,它将返回部分计数或错误设置为   如果没有收到数据,请[EAGAIN]或[EWOULDBLOCK]。默认为此   option为零,表示接收操作不会   超时。此选项采用timeval结构。请注意,并非所有   实现允许设置此选项。

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

还相关:setting timeout for recv fcn of a UDP socket

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

2 个答案:

答案 0 :(得分:3)

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

了解网络传输如何在较低层次上发生;你有一张网卡。由于此卡接收数据,无论您的程序在做什么,它都会将数据存储到自己的存储区中。当你打电话给recv;你要求操作系统将数据从网卡内存移动到你的程序内存。这意味着如果在您的线程执行其他操作时数据包进入;它不仅仅被删除,而是在您的线程下次获取数据时处理。

如果您的主题没有经常调用recv;然后网卡的内存将变满。发生这种情况时,不能存储新的数据包;如果它使用TCP,那么路由器将被告知它无法处理它;如果它是UDP,那么它将被简单地删除。正是这一部分使UDP本身不可靠,因为它可能在数据包传输过程中的任何时刻发生。

超时会影响线程等待数据出现在网卡内存区域的时间;除非你再也不打电话给recv;不会影响丢弃的数据包。

答案 1 :(得分:0)

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

<块引用>

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

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

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

  • POSIX 提到了 SO_RECVTIMEO,但 does not require it
  • 在 Windows 上,rcv() 中的超时将 put the socket in a bad state,之后您应该立即关闭它。在 POSIX 上,您可以(根据我的经验)在由 SO_RECVTIMEO 引起的超时后仍然使用套接字,但有人可能会争辩说这不是规范 100% 保证的