我在PHP中使用流式套接字从远程服务器读取.当远程服务器在连接后消失时,stream_select继续在流的读取部分上显示已更改的流,但正在读入的数据是空字符串.
这是一个重现错误的小案例.它是两个组件,服务器和客户端组件.
为了复制该bug,您需要从命令行使用php执行以下操作:
1.启动server.php
2.启动client.php
此时服务器应显示"按返回继续....或CTRL-C",客户端应显示"杀死您的服务器".按返回继续....'
此时您应该看到来自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");
?>
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
解决了这个问题.根据http://au.php.net/manual/en/function.stream-select.php上的php文档
将监视读取数组中列出的流以查看字符是否可用于读取(更确切地说,查看读取是否不会阻塞 - 特别是,流资源在文件结束时也已就绪,在这种情况下一个fread()将返回一个零长度的字符串).
当远程端消失时,这个0长度的字符串返回情况被触发,但是没有在中断检查中被捕获.
修复是测试fread返回的长度,如果是0,则退出循环.
| 归档时间: |
|
| 查看次数: |
3802 次 |
| 最近记录: |