PHP stream_socket_accept因阻塞TLS套接字而挂起

时间:2018-07-04 10:23:24

标签: php sockets websocket stream

我正在使用PHP阻止套接字,并且遇到了一个奇怪的问题。

最近,很少有用户将其websocket服务器随机挂起。 我设法发现这是由客户端的网络故障(过载/不稳定或计算机性能低下)引起的。

我终于能够使用Clumsy重现该错误,模拟数据包丢失,滞后,节流等问题,迫使客户端随机重新连接。 数小时的日志调查之后,似乎永远占据了上风:

// Note : $this->socket is a blocking TLS socket (resource type : stream)
$new = stream_socket_accept( $this->socket, 2 );

套接字元数据(由stream_get_meta_data($ this-> socket)返回):

array(
  'stream_type'  => 'tcp_socket/ssl',
  'mode'         => 'r+',
  'unread_bytes' => 0,
  'seekable'     => false,
  'timed_out'    => false,
  'blocked'      => true,
  'eof'          => true,
)

此行在processMasterSocket()中,在此处调用:

stream_select( $read, $w = null, $e = null, $this->options['timeout_select'], $this->options['timeout_select_microsec'] );
foreach( $read as $socket ) 
{
  if( $socket == $this->socket->getResource() ) 
    $this->processMasterSocket();
  else 
    $this->processClientSocket( $socket );
}

问题在于stream_socket_accept()要么花费0.0003s,200.0s,要么永远!

我已经阅读了有关阻止套接字怪异行为的信息,但是到目前为止,我们无法切换到非阻止模式(因为这将需要完全重写我们的TLS /安全代码)。 同样,不启用糟糕的网络模拟器也没有问题。

这是我的问题:

  • 为什么stream_socket_accept()有时需要花费很长的时间,而完全忽略了参数中给出的2s超时?

  • 如果它正在等待数据(由于阻止模式),为什么stream_select()告诉我有些东西要读?

  • stream_select()可以在丢包时正确地与阻塞套接字一起工作吗?

  • stream_socket_accept()是否有阻止套接字超时的方法?

1 个答案:

答案 0 :(得分:1)

发现该问题与PHP本身有关。 我忘了提到我正在运行PHP 5.3.3,而我刚遇到了这个https://bugs.php.net/bug.php?id=41631

PHP 5.4.33中修复了有关SSL阻止套接字不超时的问题

我刚刚在PHP 7.x上尝试了我的代码,它运行流畅,在60秒后超时(这是default_socket_timeout值)。

真的希望这会有所帮助,即使大多数人应该已经升级到PHP 7.x了;)