【问题标题】:PHP socket_accept throws warnings in non-blocking modePHP socket_accept 在非阻塞模式下抛出警告
【发布时间】:2013-10-20 18:28:00
【问题描述】:

我想创建一个简单的 PHP 服务器(基于 TCP),它可以提供实际时间并立即关闭连接。我已经这样做了。我想添加 crtl-C 处理,所以我需要用非阻塞替换阻塞 socket_accept (这是因为当到达阻塞 socket_accept 指令并且我发送 SIGINT /ctrl-C/ 然后服务器仍然是活动的,直到第一个客户端是服务器,然后它自行关闭 - 我不希望这种行为)。

我当前的代码如下所示:

<?php

error_reporting(E_ALL);
ob_implicit_flush();

if ($argc != 2)
    die("Wrong params");

$address = 'localhost';
$port = $argv[1];

if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false)
    die(socket_strerror(socket_last_error()) . "\n");

if (socket_bind($sock, $address, $port) === false)
    die(socket_strerror(socket_last_error($sock)) . "\n");

if (socket_listen($sock, 5) === false)
    die(socket_strerror(socket_last_error($sock)) . "\n");

socket_set_nonblock($sock);

$remote_host = $remote_port = $msgsock = null;

declare(ticks = 1);

function sig_handler($signo)
{
    switch ($signo) {
        case SIGTERM:
        case SIGINT:
            global $sock;
            socket_shutdown($sock);
            socket_close($sock);
            echo "Terminating...\n";
            exit;
    }
}

pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGINT, "sig_handler");

echo "Starting server\n";

while (1) {
    do {
        $msgsock = socket_accept($sock);
        usleep(100000);
    } while ($msgsock === false);

    socket_getpeername($msgsock, $remote_host, $remote_port);
    echo "Connection made from {$remote_host}:{$remote_port}\n";

    $msg = date('r', time()) . "\n";
    socket_write($msgsock, $msg, strlen($msg));
    socket_close($msgsock);
};

socket_close($sock);

除了一个细节外,一切正常...我每 0.1 秒(= 100000 微秒)收到以下 PHP 警告:

PHP Warning:  socket_accept(): unable to accept incoming connection [11]: Resource temporarily unavailable in /home/tomasz/Development/Python/twisted/time-server.php on line 55
PHP Stack trace:
PHP   1. {main}() /home/tomasz/Development/Python/twisted/time-server.php:0
PHP   2. socket_accept() /home/tomasz/Development/Python/twisted/time-server.php:55

我试图实现的是非阻塞接受:PHP 使用服务器套接字,检查是否有任何连接等待服务。我没有 - 等待 0.1 秒。如果有挂起的连接,则提供它。所有功能都可以,除了我不知道为什么会抛出这个警告——我只是想检查是否有任何连接需要服务。将error_reporting 修改为E_ERROR 会使警告安静下来,但我希望有更好的方法来解决这个问题...


编辑:

socket_accept($sock) 修改为 @socket_accept($sock) 只会阻止警告被抛出,但这仍然没有说明它被抛出的原因......

【问题讨论】:

    标签: php sockets networking


    【解决方案1】:

    我在寻找完全相同的问题的解决方案时找到了您的问题。此外,我发现其他一些帖子询问同样的事情,但也没有解决方案。一些帖子指出,没有办法阻止socket_accept() 发出警告,因为它是有意表明“没有等待连接来接受”。我无法确认这一点,因为 socket_accept() 的 PHP 手册页中似乎没有提到它

    和你一样,我对使用任何类型的错误抑制都不满意。似乎下一个合乎逻辑的步骤是将socket_accept() 包装在某种条件中,这样它只有在我知道有连接等待时才会执行。我找不到任何这样做的东西。但是当使用stream_*() 函数而不是仅仅socket_*() 函数时,它看起来就像有。所以我转而使用流(似乎还有其他一些优点),如下:

    if (( $socket = stream_socket_server( "tcp://$address:$port", $errno, $errstr )) === FALSE ) {
        die( "failed to create socket: $errstr\n" );
    }
    
    echo "Waiting for clients to connect...\n";
    
    while ( $server_listening ) {
        $read  = array( $socket );
        $array = array();
    
        if ( stream_select( $read, $array, $array, 0 )) {
            $connection = stream_socket_accept( $socket, 0 );
    
            client_handler( $socket, $connection );
        } else {
            usleep( 100 );
        }
    }
    

    这似乎运作良好。我的脚本仅在首先确定有连接等待时才尝试接受连接。在经历了这个之后,我确实发现有一个等效的套接字函数socket_select(),它的工作方式似乎相同。因此,如果您想坚持使用 socket_*() 函数,您也许可以做类似的事情。

    顺便说一句,我很高兴我切换到流,因为它们看起来更易于使用。由于我的应用程序仅限于 TCP,因此我似乎没有缺少任何可以通过更多低级套接字获得的功能。

    【讨论】:

      【解决方案2】:

      有一些东西可以做到这一点,那就是 select()。非阻塞套接字 IO 应该使用 select(),句号。在 PHP 中,这意味着 socket_select()。有关更多信息,请参阅有关 BSD 套接字的任何参考。

      【讨论】:

        猜你喜欢
        • 2011-07-14
        • 2012-01-01
        • 2019-06-30
        • 1970-01-01
        • 1970-01-01
        • 2012-01-14
        • 2013-11-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多