socket_select returns false immediately buth without error code
我正在玩
- 立即返回,而不是等待5秒
- 返回false,表明有错误
-
但是
socket_last_error() 返回0(成功)。
此服务器的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | $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 |
这是怎么回事
更新的测试脚本:仍可立即运行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | header('Content-Type: text/plain; charset=utf-8'); error_reporting(-1); for( $i = 0; $i < 4; $i++ ){ for( $j = 0; $j < 5; $j++ ){ echo"\ \ \ \ \ [i,j]=[{$i},{$j}]\ "; $socket = socket_create( AF_UNIX, SOCK_STREAM, 0 ); var_dump('socket_create', $socket ); echo"\ "; 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"\ "; if( $r === false ) continue; $r = socket_listen( $socket ); var_dump('socket_listen', $r ); echo"\ "; 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"\ "; var_dump('?$read/$write/$except:',$read,$write,$except);echo"\ "; var_dump('?error:', socket_last_error(), socket_strerror(socket_last_error()) );echo"\ "; var_dump('time: ', microtime(true) - $t );echo"\ "; // almost zero }} |
检查一下
http://php.net/manual/zh/function.socket-select.php
Due a limitation in the current Zend Engine it is not possible to pass a constant modifier like NULL directly as a parameter to a function which expects this parameter to be passed by reference. Instead use a temporary variable or an expression with the leftmost member being a temporary variable:
所以问题是您正在初始化
您可能要使用stream_ *函数而不是套接字。
流函数更通用,并且是PHP核心的一部分,而需要安装Socket支持。 流功能从根本上给了您更多的控制权。
http://www.php.net/manual/zh/intro.stream.php
正如@Amez指出的那样,您不应传递空值来进行选择。 而是,为未使用的
1 2 3 4 | $read = array( $server ); $write = array(); $except = array(); $changed = socket_select( $read, $write, $except, 5,0 ); |
我最近偶然发现了python中的相同问题(我不知道为什么PHP / Python不会在内部简单地用空数组替换null值,因为选择select似乎是预期的行为)。
如果遇到此错误,则可以使用类似的方法来解决:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $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 ); } } |