Я работаю с блокирующими сокетами в 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()
тайм-аута с блокирующими розетками?