PHP套接字服务器,检查客户端是否处于活动状态


PHP socket server, check if client is alive

我有一个php服务器在监听1c#客户端。

当建立连接时,它保持活动,直到客户端发送命令"0";退出";这会杀死PHP服务器。

但是当c#客户端断开连接时;退出";命令(即:单击windows窗体中的关闭(x)按钮)服务器只是继续侦听,无法从该客户端接收任何其他连接。

有没有办法从服务器端(PHP)检查与客户端的连接是否仍然有效?

我的php服务器代码基于以下示例1:http://php.net/manual/en/sockets.examples.php

如果有人对重现错误/错误行为感兴趣,请粘贴示例1中的代码:http://php.net/manual/en/sockets.examples.php,通过telnet从局域网中的远程客户端连接,拔下客户端电线。。。php服务器将永远存在,不接受任何新的连接。

在循环中,您需要检查socket_read()的返回值。如果返回FALSE,则表示存在读取错误(可能是由远程主机关闭连接引起的)。您提供的链接中的示例代码涵盖了这种情况。

如果您需要优雅地处理某些错误状态,您可以始终使用socket_last_error()检查套接字错误代码——本说明描述了可能的代码。

编辑:

当使用putty进行telnet时,如果我用X按钮关闭,那么在PHP中连接是正确关闭的,但如果我拔下putty机器的以太网线,PHP服务器就会挂起。

关闭PuTTY时关闭连接的原因是PuTTY在退出时关闭其打开的连接。这导致socket_read()返回错误代码(我相信ECONNRESET)。如果你拔掉网络电缆,它就没有机会这么做了。

根据您的网络配置方式,TCP连接最终应失败。您可以尝试通过用socket_set_option()设置SO_RCVTIMEO来控制超时,但这并不总是适用于所有平台(我看着你,WinSock)

或者,您可以使用socket_select()在合理的超时时间内滚动自己的轮询循环。如果在超时后,连接的套接字都没有要发送的数据,则终止服务器。

我通过检查socket_select() $read数组是否包含有问题的连接,但socket_read()数据为空(两次)来完成此操作。

似乎socket_select()将断开连接的客户端添加到$read阵列,并且socket_read()在尝试读取断开连接客户端的数据时给出空字符串''

以下代码将显示连接状态。

  $address='example.com';
    $port = '9065';
    if (isset($port) && ($socket=socket_create(AF_INET, SOCK_STREAM, SOL_TCP))
     && (socket_connect($socket, $address, $port)))  {
    $text="Connection successful on IP $address, port $port";
    socket_close($socket);
    }
    else  {
    $text='Unable to connect<pre>'.socket_strerror(socket_last_error()).'</pre>';
    }
    echo $text;

正如Michael Dodd所说,使用socket_select()可以使所有已接收数据的套接字加上已关闭的套接字。此外,您还可以拥有其缓冲区可以接受数据进行传输的所有缓冲区,和/或引发某些异常的缓冲区。如果有这个信息,套接字数组的(单独的)副本必须放在函数的第二个和/3d参数中。(如果不需要,此函数必须将$null作为等于null的变量,而不仅仅是null)

以下示例显示了如何读取数据并在套接字仍然打开的情况下测试套接字。我将此代码用于由socket_accept()在侦听套接字上创建的套接字,它可以正常工作。可以使用socket_read而不是使用socket_recv。

//all sockets created have been inserted to an array $socketArray
//get a copy of the sockets array
$tempArray = $socketArray;
//this command will remove from $tempArray all sockets that have no data and are alive, with a timeout of 0 sec, 100 msec
socket_select($tempArray, $null, $null, 0, 100);
if (count($tempArray)) {
    //if we have some sockets in the array
    foreach($tempArray as $socket) {
        //read some data
        $count = socket_recv($socket, $socketData, 1024, 0);
        if ($count) {
            //your code to do what you want with $socketData
        } else {
            //find socket position in initial socket array
            $index = array_search($socket, $socketArray);
            //if found, remove it from array and close the socket
            if ($index !== false) {
                array_splice($socketArray, $index, 1);
                socket_close($socket);
            }
        }
    }
}