php' socket_select()方法是否可以保证检测所有客户端套接字断开连接?
我已经看到一些代码示例在php的socket_select()方法中使用read数组来检测客户端套接字断开连接,例如: How to detect client disconnection on PHP socket listener?
但是对于所有客户端套接字断开,它是否返回FALSE?如果有任何例外,它们是什么?
答案 0 :(得分:6)
<强> TL; TR 强>
您需要定期发送包含零长度数据的TCP pakets,并等待来自客户端的ACK
以确保它没有物理断开连接。否则socket_select()
将假定如果客户端物理断开连接仍然打开连接。在Linux上,内核可以提供帮助 - 它被称为TCP keep-alives
<强>解释强>
问题是您对ALL
类型的客户端断开连接意味着什么?在评论中,您表示您担心不合适的客户端断开连接。如果在客户端发生停电会怎么样?
首先是关于优雅客户端断开连接的简短句子。在TCP中,客户端可以通过两种方式关闭连接:向服务器发送FIN
数据包或发送RST
数据包。 (后者不太可能发生在客户端)。 socket_select()
了解这两种方式如何优雅地实现脱节。
如果客户端在连接打开时物理断开连接,则无法再发送FIN
或RST
数据包。出现这种情况可能是因为停电,缺陷电缆,缺陷开关等原因很多......
在这种情况下,连接将永远保持在服务器端打开,因为TCP没有实现超时,这意味着它不需要发送数据包。成功连接后,除非收到FIN
或RST
数据包,否则连接将保持打开状态。
所以如何检测断开的连接是不可能的?不,还有办法如何检测这些。该概念称为TCP keep-alive
数据包。
TCP keep-alives
基于TCP协议的一项功能:当您在TCP中发送数据时,接收方会以ACK
数据包响应,表示收到的数据包成功。 TCP keep-alive
数据包是包含零长度数据的数据包,只是为了在客户端上触发ACK
数据包。请注意,客户端不需要实现keep-alives
。它很简单TCP
。
在Linux上,内核可以帮助发送keep-alives
。如果在给定(可配置)超时内没有在套接字上收到数据,则内核将发送这些零长度数据包并在没有收到ACK
且具有可配置的时间量时关闭套接字。还有一个可配置的重试间隔。如果内核关闭了套接字,socket_select()
就会知道它。
了解如何在Linux上配置TCP keep-alives
:http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
不幸的是,我没有在其他操作系统上使用TCP keep-alives
的经验,但我想也支持类似的东西。