我找到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消息时发生超时的情况。
答案 0 :(得分:3)
没有;它不会让你更有可能丢弃数据包。
了解网络传输如何在较低层次上发生;你有一张网卡。由于此卡接收数据,无论您的程序在做什么,它都会将数据存储到自己的存储区中。当你打电话给recv;你要求操作系统将数据从网卡内存移动到你的程序内存。这意味着如果在您的线程执行其他操作时数据包进入;它不仅仅被删除,而是在您的线程下次获取数据时处理。
如果您的主题没有经常调用recv;然后网卡的内存将变满。发生这种情况时,不能存储新的数据包;如果它使用TCP,那么路由器将被告知它无法处理它;如果它是UDP,那么它将被简单地删除。正是这一部分使UDP本身不可靠,因为它可能在数据包传输过程中的任何时刻发生。
超时会影响线程等待数据出现在网卡内存区域的时间;除非你再也不打电话给recv;不会影响丢弃的数据包。
答案 1 :(得分:0)
答案是否定的,丢失 UDP 数据将违反POSIX:
<块引用>recv() 函数应返回写入缓冲区参数所指向的缓冲区的消息长度。 对于基于消息的套接字,例如 SOCK_DGRAM 和 SOCK_SEQPACKET,应在单个操作中读取整个消息。
据推测,“部分计数”仅在使用 MSG_WAITALL
选项时基于连接的套接字发生。
话虽如此,通常不赞成使用 SO_RECVTIMEO
,而在套接字上实现超时的“正确”方法是使用非阻塞套接字和 select()
。这是出于历史原因,而不是因为设置超时在某种程度上本质上是糟糕的设计或其他什么。如果您坚持使用 SO_RECVTIMEO
,请注意潜在的可移植性问题:
SO_RECVTIMEO
,但 does not require itSO_RECVTIMEO
引起的超时后仍然使用套接字,但有人可能会争辩说这不是规范 100% 保证的