简体   繁体   English

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

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

I have a php server listening for 1 c# client.我有一个 php 服务器监听 1 个 c# 客户端。

When a connection is established, it is kept alive until client sends the command "quit" which kills the PHP server.建立连接后,它会一直保持活动状态,直到客户端发送杀死 PHP 服务器的命令“quit”。

But when the c# client disconnects without the "quit" command (ie : clicking the close (x) button in the windows form) the server just keep listening, and can't receive any other connection from that client.但是,当 c# 客户端在没有“退出”命令的情况下断开连接时(即:单击 Windows 窗体中的关闭 (x) 按钮),服务器只会继续侦听,并且无法从该客户端接收任何其他连接。

Is there a way to check from the server side (PHP) if connection is still alive with client?有没有办法从服务器端(PHP)检查客户端的连接是否仍然有效?

My php server code is based on example1 of: http://php.net/manual/en/sockets.examples.php我的 php 服务器代码基于以下示例 1: http : //php.net/manual/en/sockets.examples.php

If someone is interested in reproducing the bug/error behavior, paste code from example1 : http://php.net/manual/en/sockets.examples.php , connect by telnet from a remote client in lan, unplug client wire... php server will hang around forever, no new connection is accepted.如果有人对重现错误/错误行为感兴趣,请粘贴 example1 中的代码: http : //php.net/manual/en/sockets.examples.php ,通过 telnet 从局域网中的远程客户端连接,拔下客户端线.. . php 服务器会一直挂着,不接受新的连接。

In your loop, you need to check the return value of socket_read() .在您的循环中,您需要检查socket_read()的返回值。 If it returns FALSE, then there was a read error (which can be caused by the remote host closing the connection).如果它返回 FALSE,则存在读取错误(这可能是由远程主机关闭连接引起的)。 The example code in the link you provided covers this case.您提供的链接中的示例代码涵盖了这种情况。

If you need to gracefully handle certain error states, you can always check the socket error code using socket_last_error() -- this note decribes the possible codes.如果你需要优雅地处理某些错误状态,你总是可以使用socket_last_error()检查套接字错误代码—— 这个注释描述了可能的代码。

Edit:编辑:

When using putty for telnet, if i close with X button, connecion is closed properly in PHP, but if i unplug the ethernet wire of the putty machine, PHP server just hangs around.使用 putty 进行 telnet 时,如果我用 X 按钮关闭,则 PHP 中的连接会正确关闭,但是如果我拔掉 putty 机器的以太网线,PHP 服务器就会挂起。

The reason that the connection is closed when killing PuTTY is that PuTTY closes its open connection(s) when exiting.杀死 PuTTY 时连接关闭的原因是 PuTTY 在退出时关闭其打开的连接。 This causes socket_read() to return with an error code (I believe ECONNRESET ).这会导致socket_read()返回错误代码(我相信ECONNRESET )。 If you pull the network cable, it doesn't have a chance to do that.如果你拉网线,它就没有机会这样做。

Depending on how your network is configured, the TCP connection should eventually fail.根据您的网络配置方式,TCP 连接最终应该会失败。 You can attempt to control the timeout by setting SO_RCVTIMEO with socket_set_option() , but this doesn't always work on all platforms (I'm looking at you, WinSock) .您可以尝试通过设置来控制超时SO_RCVTIMEOsocket_set_option()但是这并不总是工作在所有平台上(我看你,的WinSock)。

Alternatively, you can roll your own polling loop using socket_select() with a reasonable timeout.或者,您可以使用socket_select()以合理的超时滚动您自己的轮询循环。 If none of the connected sockets have data to send after your timeout, then kill the server.如果超时后连接的套接字都没有数据要发送,则终止服务器。

The following code will show the state of connection.以下代码将显示连接状态。

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

I did this by checking if the socket_select() $read array includes the connection in question but socket_read() data is empty (twice).我通过检查socket_select() $read数组是否包含有问题的连接但socket_read()数据为空(两次)来做到这一点。

It seems that socket_select() adds disconnected clients to the $read array and socket_read() gives an empty string '' when trying to read the disconnected client's data.似乎socket_select()将断开连接的客户端添加到$read数组中,而socket_read()在尝试读取断开连接的客户端的数据时给出了一个空字符串''

As Michael Dodd says, using socket_select() can have all sockets that have received data plus those they have closed.正如迈克尔·多德所说,使用 socket_select() 可以拥有所有已接收数据的套接字以及它们已关闭的套接字。 Also you can have all those that their buffer can accept data for transmission, and / or those that have raised some exception.您也可以拥有所有缓冲区可以接受数据进行传输的内容,和/或引发某些异常的内容。 Do have this info, a (separate) copy of sockets array must be placed in 2nd and / 3d parameter of function.确实有这个信息,套接字数组的(单独的)副本必须放在函数的第二个和 / 3d 参数中。 (if not needed, this function must have $null as a variable equal to null, not just null) (如果不需要,此函数必须将 $null 作为等于 null 的变量,而不仅仅是 null)

The following example shows how to read data and test sockets if they are still open.以下示例显示了如何读取数据并测试套接字仍处于打开状态。 I am using this code for sockets that have been created by socket_accept() on a listening socket, and it is working without problems.我将此代码用于由 socket_accept() 在侦听套接字上创建的套接字,并且它可以正常工作。 Instead of using socket_recv, socket_read can be used.可以使用 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