PHP stream_socket_accept зависает с блокировкой сокетов TLS - PullRequest
0 голосов
/ 04 июля 2018

Я работаю с блокирующими сокетами в PHP, и у меня возникла странная проблема.

В последнее время лишь немногие пользователи зависали в случайном порядке. Мне удалось выяснить, что это было вызвано плохой сетью (либо перегруженной / нестабильной, либо просто дерьмовым компьютером) на стороне клиента.

Мне наконец-то удалось воспроизвести ошибку с помощью 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,0003, 200,0 или навсегда!

Я уже читал о странном поведении блокировки сокетов, но на данный момент мы не можем переключиться в неблокирующий режим (так как для этого потребуется полная перезапись нашего TLS / защищенного кода). Опять же, нет проблем без включенного дерьмового сетевого симулятора.

Итак, вот мои вопросы:

  • Почему stream_socket_accept() иногда занимает вечность, полностью игнорируя время ожидания 2 с, указанное в параметре?

  • Если он ожидает данных (из-за режима блокировки), почему stream_select() сказал мне, что есть что прочитать?

  • Правильно ли работает stream_select() с блокирующими сокетами при потере пакетов?

  • Есть ли способ для stream_socket_accept() тайм-аута с блокирующими розетками?

1 Ответ

0 голосов
/ 05 июля 2018

Обнаружено, что проблема связана с самим 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;)

...