【问题标题】:Is php's socket_select() guaranteed to detect all client socket disconnections?php 的 socket_select() 是否保证检测到所有客户端套接字断开连接?
【发布时间】:2015-02-25 07:45:35
【问题描述】:

php 的socket_select() 方法是否保证检测到所有客户端套接字断开连接?

我看过一些代码示例,它们使用 php 的 socket_select() 方法中的读取数组来检测客户端套接字断开连接,例如这个: How to detect client disconnection on PHP socket listener?

但是对于所有客户端套接字断开连接它是否返回 FALSE?如果有任何例外,它们是什么?

【问题讨论】:

  • 为什么会有例外?
  • @hek2mgl 这不是我是否期望异常的问题。这是一个我应该期待例外的问题吗?
  • 不,您不需要期待异常。我真的应该回答吗?!
  • @hek2mgl 如果是正确的,我会很高兴。但是你能支持你的回答来支持你的主张吗?
  • 顺便说一句,我说的只有FIN才能关闭连接是错误的。 RST 也是可能的。可能还有更多的方法?我没想到,但我不是超级 tcp 专家。但是我会说 socket_select() 会意识到这一点,因为底层内核处理低级 TCP。我希望内核能够正确实现 TCP,但是,嘿! :)

标签: php sockets


【解决方案1】:

TL;TR

您需要定期发送包含零长度数据的 TCP 数据包,并等待来自客户端的 ACK 以确保它没有物理断开连接。否则,socket_select() 将假定客户端在物理上断开连接时连接仍处于打开状态。在 Linux 上,内核可以提供帮助 - 它被称为 TCP keep-alives


说明

问题是ALL 类型的客户端断开连接是什么意思。在 cmets 中,您表示您担心不正常的客户端断开连接。如果客户端断电会怎样?

首先是关于优雅的客户端断开连接的简短句子。在 TCP 中,客户端关闭连接的方式有两种:向服务器发送FIN 数据包或发送RST 数据包。 (后者不太可能发生在客户端)。 socket_select() 知道这两种方式如何优雅地断开连接。

如果客户端在连接打开时物理断开连接,则无法再发送FINRST 数据包。发生这种情况的原因有很多,例如停电、电缆故障、开关故障等...

在这种情况下,服务器端的连接将永远保持打开状态,因为 TCP 没有实现超时,这意味着它不需要发送数据包。成功连接后,连接保持打开状态,除非收到FINRST 数据包。

所以没有机会如何检测断开的连接?不,仍然有一种方法可以检测到这些。这个概念被称为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-aliveshttp://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html

不幸的是,我没有在其他操作系统上使用 TCP keep-alives 的经验,但我想它也支持类似的东西。

【讨论】:

  • 是否有任何示例如何使用 php socket_select 的“异常”参数?
猜你喜欢
  • 2010-12-20
  • 1970-01-01
  • 2013-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-14
  • 2011-04-29
  • 1970-01-01
相关资源
最近更新 更多