为何调用TCPSocket的write方法会出现无限挂起的问题?
什么情况下TCPSocket的write方法会无限挂起
默认Ruby的TCPSocket工作在阻塞模式下,write调用会一直等待直到所有数据全部写入操作系统的TCP发送缓冲区为止,如果缓冲区被占满且长时间无法释放,就会出现无限挂起的情况,对应示例代码如下:
lotsOfBytes = # a really large number of bytes, like 1 or 2 MB of data socket = TCPSocket.new # some config socket.write(lotsOfBytes) # this line hangs
常见触发场景
- 接收端TCP接收缓冲区已被占满,且接收端进程没有主动从缓冲区读取数据,此时TCP滑动窗口变为0,发送端会停止发送动作,
write调用会一直阻塞等待接收端的窗口更新通知。大key量get_multi请求场景大概率属于这类:一次性发送的请求体过大,超出memcached单次接收处理的阈值,导致memcached没有及时读取缓冲区数据,发送端缓冲区占满后write就会挂起。 - 网络链路出现异常中断,TCP重传达到操作系统设定的最大重试次数后也没有恢复连接,且操作系统没有主动断连的情况下,
write操作会一直阻塞。 - 接收端进程进入僵死、不可中断休眠状态,既不会读取缓冲区数据,也不会主动断开连接,发送端的发送缓冲区占满后
write就会永久挂起。
规避方案
可以给套接字设置非阻塞模式,配合IO.select检测可写状态再执行写操作,也可以手动设置套接字的发送超时时间,避免永久挂起。
内容的提问来源于stack exchange,提问作者esilver
相关产品推荐
相关产品推荐

