PHP stream_select продолжает запускать пустые события чтения после исчезновения удаленного соединения - PullRequest
2 голосов
/ 28 февраля 2011

Я использую потоковые сокеты в PHP для чтения с удаленного сервера.Когда удаленный сервер отключается после подключения, stream_select продолжает показывать измененный поток в части чтения потока, но считываемые данные представляют собой пустую строку.

Вот небольшой случай, который воспроизводит ошибку,Это два компонента, сервер и клиентский компонент.

Чтобы повторить ошибку, вам нужно будет сделать следующее, используя php из командной строки:
1. Запустите server.php
2. Запустите client.php

. На этом этапе на сервере должно появиться сообщение «Нажмите return для продолжения .... или CTRL-C», а на клиенте - «Убить ваш сервер».Нажмите return для продолжения .... '

  1. Ctrl-c server.php
  2. Нажмите enter на client.php

На этом этапе вам следуетсм. отладочный вывод из client.php, показывающий проблему (вам нужно довольно быстро нажать ctrl-c, он очень быстро печатает много повторяющейся информации)

Я не уверен, почему stream_select продолжает показывать поток чтения какизменения после того, как серверный компонент больше не работает.

server.php

<?php
  $socket = stream_socket_server("tcp://0.0.0.0:51111", $errno, $errstr);
  $s = stream_socket_accept($socket);

  print("Press return to continue.... or CTRL-C me");
  fread(STDIN,1); // Wait for one character to be pressed.
  fwrite($s, "Yep here's some stuff for you\0");
?>

client.php

<?php
$url = "localhost";
$port = 51111;

$errno = 0;
$errstr = "";

$fp = @stream_socket_client("tcp://".$url.":".$port, $errno, $errstr, 5);
if (!$fp) 
{
  print( "Unable to open socket: $errstr ($errno)\n" );
  throw new Exception( "Unable to open socket : $errstr ($errno)" );
}

//WAIT HERE.
print("Kill your server. ");
print("Press return to continue....\n\n");
fread(STDIN,1); // Wait for one character to be pressed.

stream_set_blocking($fp,0);

$buffer = "";

while ( true )
{
    $read   = array($fp);
    $write  = NULL;
    $except = array($fp);

    //Wait for up to 5 second to get something from the server
    if (false === ($num_changed_streams = stream_select($read, $write, $except, 5)))
    {
        // It timed out!
        fclose($fp);
        print( "Socket internal error\n" );
        throw new Exception( "Socket internal error" );
    }

    if( empty($read) ) //It must be an excecption instead...
    {
        // We got a socket error
        fclose($fp);
        print("Socket error\n");
        throw new Exception( "Socket Error" );
    }

    print( var_export( array( $read, $write, $except), true )."\n" );
    print( "Num changed streams: $num_changed_streams\n" );

    if ( $num_changed_streams == 0 )
    {   
        // nothing changed int he stream, we hit a timeout!
        fclose( $fp );
        print( "Socket timeout\n" );
        throw new Exception( "Socket timeout" );
    }

    //We're ready to read.       
    $chunk = fread($fp, 1024);
    if( $chunk === FALSE )
    {
        print("fread failed\n");
        throw new Exception("fread failed");
    }
    print( "Chnk: ".var_export( $chunk, true )."\n" );

    $buffer.= $chunk;
    if ( (strlen($chunk)>0) && (ord($chunk[strlen($chunk)-1])==0) ) break;
}
fclose($fp);

1 Ответ

5 голосов
/ 01 марта 2011

сработало это. Согласно документации php на http://au.php.net/manual/en/function.stream-select.php

Потоки, перечисленные в массиве чтения будет наблюдаться, чтобы увидеть, если персонажи стать доступным для чтения (подробнее точно, чтобы увидеть, если чтение не будет блок - в частности, поток ресурс также готов к концу файла, в этом случае fread () вернет строка нулевой длины).

Этот случай возврата строки 0 длины был запущен, когда удаленный конец ушел, но не был пойман при проверке на разрыв.

Исправлено, чтобы проверить длину возврата от fread, и если она равна 0, то вырваться из цикла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...