非阻塞套接字如何出现发送超时?

9

我在理解Linux中套接字的工作方式时遇到了一些问题。

setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(int));
write = write(sockfd, buf, len);

在上述代码中,由于写入是缓冲的,因此发送超时没有任何意义(当用户空间缓冲区被复制到内核缓冲区时,写系统调用将立即返回)。发送缓冲区大小是更重要的参数,但似乎发送超时并没有什么值得注意的作用。但我肯定是错的,因为我见过很多使用SO_SNDTIMEO的代码。如果接收者非常缓慢,用户空间代码如何使用SO_SNDTIMEO进行超时?

你能澄清一下你想要达到什么结果吗? - Alexey Feldgendler
2
我并没有试图达到任何结果,我提出这个问题是为了了解套接字的工作原理,特别是为什么SO_SNDTIMEO存在? - 0xhacker
这个答案可能会帮助您理解 SO_SNDTIMEO:https://dev59.com/questions/xm855IYBdhLWcg3wuG0M#4182564 - Alexey Feldgendler
1
@Alexey Feldgendler - 这是一个有效的问题。如果SO限制自己只回答“实际”的问题,他们将不得不删除20%的问题。这里已经有很多令人头痛的晦涩问题被提出并得到了解答。 - Duck
1
我能想到的唯一设置非阻塞套接字上的 SO_SNDTIMEO 的原因是,在代码库中的某个地方,套接字被设置回阻塞模式(可能仅针对特定操作暂时性地),并且代码的作者希望在它被设置回阻塞模式的时间内,套接字具有超时功能。 (或者同样可能的是,应用程序最初是使用阻塞模式套接字编写的,后来转换为使用非阻塞套接字,而代码的作者只是忘记删除现在不再需要的 SO_SNDTIMEO 调用) - Jeremy Friesner
2个回答

13
怎么可能在非阻塞套接字上设置发送超时?
不可能。超时是针对阻塞模式的。非阻塞的recv()或send()不会阻塞,因此也无法超时。
我见过很多使用SO_SNDTIMEO的代码。
除非相关代码是无意义的,否则在非阻塞模式下不会使用它。
如果你想在非阻塞模式下设置超时,那就是select()中的超时机制之一。

在Linux中,如何确保发送或写入数据包是阻塞的,即只有当内核接收到整个缓冲区(缓冲区将被分解成多个TCP数据包)的ACK时,write或send才会返回。 - 0xhacker
@mc_87 你不能这样做。如果你想要一个确认,你将不得不在应用程序层面上自己发送一个。 - user207421
那么,如果在应用程序层面上无法阻塞直到最后一个TCP ACK,那么SO_SNDTIMEO如何有用呢? - 0xhacker
@mc_87 超时是指在阻塞模式下将数据发送到已满的套接字发送缓冲区或从空的套接字接收缓冲区接收数据时发生的阻塞。关于在发送时等待ACK的部分只是你的想象。TCP是一种流协议,而不是请求/响应协议。 - user207421

5

SO_SNDTIMEO对于阻塞套接字非常有用。如果套接字的缓冲区已满,send()函数会被阻塞,此时使用SO_SNDTIMEO套接字选项可能很有用。对于非阻塞套接字,如果套接字的缓冲区已满,则send()将立即失败,因此在非阻塞套接字上设置SO_SNDTIMEO没有意义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接