套接字上的阻塞send()可以等待吗?

时间:2014-05-03 16:50:14

标签: sockets

我有一个问题要解决我仍然不太熟悉的大块代码,如果我的问题没有很好地制定,那就很抱歉...

代码包含2个通过套接字进行通信的进程。每个进程都包含许多线程,这些线程使用递归的互斥体进行数据保护。当运行很长一段时间代码挂起 - 根据转储我有一个线程阻塞在互斥上等待而另一个线程持有它并且似乎卡在send()中 - 我已检查并发送()是阻止。 但是,有人告诉我,一个线程不能永远阻塞send() - 如果接收对等体死了",将检测到连接不再存在的事实,send()最终会返回一个错误代码 - 这似乎是有道理的,因为我会认为应该有一些"我还活着#34;在连接的对等体之间交换的消息。

但是当我用Google搜索"时,在我看来这不是真的 - 如果send()阻塞,因为网络缓冲区中没有空间而我的同伴"死亡"如果不发出close(),我的send()实际上将被永久阻止。 (和"我还活着#34;默认情况下不会交换消息......?)

如果有人可以确认/解释当接收对等方死亡时阻塞发送()发生了什么,我将非常感激。

提前谢谢大家。

4 个答案:

答案 0 :(得分:1)

如果对等体意外死亡,则操作系统可能需要很长时间才能检测到它并使套接字连接无效。您可以通过在代码中使用超时来避免此问题。切换到非阻塞套接字。或者在调用阻塞select()之前使用send()来检测套接字是否可写。或者使用SO_SNDTIMEO的{​​{1}}选项设置阻止发送的超时。或启用TCP keepalive。

答案 1 :(得分:1)

你是对的,你的googled资源是错误的。本地套接字发送缓冲区已满时发送()块。如果对等计算机已崩溃,它将停止向当前位于TCP已尝试发送的套接字发送缓冲区中的所有数据发送ACKS,因此本地TCP将最终重置连接并取消阻止发送。这就是发送是检测连接失败的唯一可靠方法的原因。

答案 2 :(得分:0)

我假设您正在使用TCP,因为使用UDP时,发送不应该阻止。只要您没有从对等方获得TCP FIN或RST,连接就不会被视为已关闭,因此发送将继续阻止。如果对等方也挂在某处,如果对等计算机崩溃或者与对等方的网络连接丢失,则可能发生这种情况。您可以使用TCP_KEEPALIVE套接字选项使TCP堆栈发送保持活动消息,但即使在这种情况下,通常需要数小时才能注意到丢失的连接(保持活动的默认超时通常为2小时)。

感谢@EJP和@WarrenDew:如果对等体不再接受数据,则窗口大小将变为0,但发送方将经常进行探测,以便检测网络问题或机器崩溃。因此,如果对等体停止,它仍然可以永久挂起,但对等体必须仍然存活且可以访问。

答案 3 :(得分:0)

正如EJP所说,如果接收机器在填充其接收缓冲区后死亡,则发送方将检测到该因为其周期性窗口探测数据包将不会收到确认。

然而,如果接收机器没问题但是接收应用程序挂起 - 这可能算作"已经死亡"根据您的Google来源 - 接收应用程序将停止使用数据,但其机器仍将继续执行窗口探测。因此挂起将传播到发送应用程序。这可能就是你的情况。