我正在玩socket_select
,但在一个主机上,这个功能做了一些奇怪的事情:
socket_last_error()
返回0(成功)。 phpinfo()
:http://jsfiddle.net/Lmrfe/embedded/result/
$server = socket_create( AF_UNIX, SOCK_STREAM, 0 );
$r = socket_bind( $server, '/some/file/somewhere');
$r = socket_listen( $server );
// none of the above socket_* returns false
$t = microtime(true);
socket_clear_error();
$read = array( $server ); $write = null; $except = null;
$read = array( $server ); $write = array(); $except = array();
$read = array(); $write = array(); $except = array();
$read = null; $write = null; $except = null;
$changed = socket_select( $read, $write, $except, 5,0 );
$changed = socket_select( $read, $write, $except, null );
$changed = socket_select( $read, $write, $except, 5000000 );
$changed = socket_select( $read, $write, $except, 5000000, 0 );
$changed = socket_select( $read, $write, $except, 5000000, 5000000 );
/* Results:
microtime(true) - $t == almost zero
$changed === false
socket_last_error() === 0
socket_strerror(socket_last_error()) === Success
$read === array(1) {
[0]=>
resource(2) of type (Socket)
}
$write === NULL
$except === NULL
*/
$s = socket_read( $server, 1024, PHP_BINARY_READ );
// $s === false
这里发生了什么?
更新的测试脚本:仍然在瞬间运行:
header('Content-Type: text/plain; charset=utf-8');
error_reporting(-1);
for( $i = 0; $i < 4; $i++ ){
for( $j = 0; $j < 5; $j++ ){
echo "\n\n\n\n\n[i,j]=[{$i},{$j}]\n";
$socket = socket_create( AF_UNIX, SOCK_STREAM, 0 );
var_dump('socket_create', $socket ); echo "\n"; if( $socket === false ) continue;
$socket_file = dirname(__FILE__)."/test_socket_i{$i}_j{$j}";
if( file_exists( $socket_file )) unlink( $socket_file );
$r = socket_bind( $socket, $socket_file );
var_dump('socket_bind', $r ); echo "\n"; if( $r === false ) continue;
$r = socket_listen( $socket );
var_dump('socket_listen', $r ); echo "\n"; if( $r === false ) continue;
$t = microtime(true);
socket_clear_error();
if($i==0){ $read = null; $write = null; $except = null; }
if($i==1){ $read = array(); $write = array(); $except = array(); }
if($i==2){ $read = array( $socket ); $write = null; $except = null; }
if($i==3){ $read = array( $socket ); $write = array(); $except = array(); }
if($j==0){ $changed = socket_select( $read, $write, $except, 5,0 ); } // 5 seconds
if($j==1){ $changed = socket_select( $read, $write, $except, null ); } // forever
if($j==2){ $changed = socket_select( $read, $write, $except, 5000000 ); }
if($j==3){ $changed = socket_select( $read, $write, $except, 5000000, 0 ); }
if($j==4){ $changed = socket_select( $read, $write, $except, 5000000, 5000000 ); }
var_dump('•socket_select returned:', $changed );echo "\n";
var_dump('•$read/$write/$except:',$read,$write,$except);echo "\n";
var_dump('•error:', socket_last_error(), socket_strerror(socket_last_error()) );echo "\n";
var_dump('time: ', microtime(true) - $t );echo "\n"; // almost zero
}}
答案 0 :(得分:3)
您可能希望使用stream_ *函数而不是socket。
流函数更通用,是PHP核心的一部分,而需要安装Socket支持。流功能可以为您提供更多控制。
答案 1 :(得分:3)
检查一下 http://php.net/manual/en/function.socket-select.php
由于当前Zend引擎存在限制,因此无法将NULL之类的常量修饰符作为参数直接传递给期望通过引用传递此参数的函数。而是使用临时变量或表达式,最左边的成员是临时变量:
所以问题是您正在初始化$write = null
答案 2 :(得分:2)
正如@Amez指出的那样,你不应该将null值传递给select。而是为未使用的socket_select()
参数创建一个空数组:
$read = array( $server );
$write = array();
$except = array();
$changed = socket_select( $read, $write, $except, 5,0 );
我最近在python中偶然发现了同样的问题(我不知道为什么PHP / Python不会简单地在内部用空数组替换空值,因为选择这肯定是预期的行为)。
答案 3 :(得分:0)
如果你遇到这个bug,你可以使用类似的东西来解决它:
$socket_select_timeout_seconds = 5;
while(true){
$time_start = microtime(true);
$c = socket_select($r,$w,$e, $socket_select_timeout_seconds );
if( /* something happened */ ){
// handle socket events
}else if( microtime(true) - $time_start < 0.01){
// nothing happened, but buggy socket_select didn't wait
// wait manually
usleep( $socket_select_timeout_seconds * 1000000 );
}
}