繁体   English   中英

PHP套接字服务器,检查客户端是否还活着

[英]PHP socket server, check if client is alive

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

建立连接后,它会一直保持活动状态,直到客户端发送杀死 PHP 服务器的命令“quit”。

但是,当 c# 客户端在没有“退出”命令的情况下断开连接时(即:单击 Windows 窗体中的关闭 (x) 按钮),服务器只会继续侦听,并且无法从该客户端接收任何其他连接。

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

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

如果有人对重现错误/错误行为感兴趣,请粘贴 example1 中的代码: 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 连接最终应该会失败。 您可以尝试通过设置来控制超时SO_RCVTIMEOsocket_set_option()但是这并不总是工作在所有平台上(我看你,的WinSock)。

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

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

  $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;

我通过检查socket_select() $read数组是否包含有问题的连接但socket_read()数据为空(两次)来做到这一点。

似乎socket_select()将断开连接的客户端添加到$read数组中,而socket_read()在尝试读取断开连接的客户端的数据时给出了一个空字符串''

正如迈克尔·多德所说,使用 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);
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM