确定客户端是否已使用套接字关闭与服务器的连接

时间:2013-08-25 20:05:08

标签: php apache sockets ubuntu websocket

我正在尝试检查客户端是否已断开连接,以便我可以关闭客户端连接以允许客户端重新连接。

我有以下内容。

$socket = @socket_create_listen("12345");

while (true) {  
    $client = socket_accept($socket);
    socket_write($client, 'hello');
    while (true) {
        //Code to exit this loop when client looses connection
        socket_write($client, '');
        echo socket_last_error($socket);
    }
    socket_close($client);  
}

尝试:

[1]向客户端写一个空字符串,希望如果客户端断开连接会产生错误,但这不起作用。

[2]使用ocket_select

$r = array($socket);
$w = NULL;
$e = NULL;
if (false === socket_select($r, $w, $e, 0)) {
    echo "socket_select() failed, reason: " .
        socket_strerror(socket_last_error()) . "\n";
}

这似乎也没有产生错误,然后客户端失去连接。

注意:我试图在服务器端实现这一点,因此发送一点并等待回复并不是我真正想要的。通常我只是写入客户端而不接收数据因此在阻塞中运行我的代码并不是一个问题,因为我通常是在写,而不是在阅读。

2 个答案:

答案 0 :(得分:0)

以下是我认为可以用来检测现有套接字的一些代码......

此代码的发起人被声明为 Andrew Gillard 没有其他许可证信息可用...

<?php

$host = '127.0.0.1';
$port = 7010;
gc_enable();

set_time_limit(0);

function socketError($errorFunction, $die=false)
{
    $errMsg = socket_strerror(socket_last_error());
    echo $errorFunction.' '.$errMsg."\n";
    if ($die) die("Program Ended\n");
}

//Attempt to create our socket. The "@" hides PHP's standard error reporting,
if (!($server = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP))) socketError('socket_create', true);
//socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);
if (!@socket_bind($server, $host, $port)) socketError('socket_bind', true);
if (!@socket_listen($server)) socketError('socket_listen', true);
 //Create an array to store our sockets in. We use this so that we can
// determine which socket has new incoming data with the "socket_select()"
// function, and to properly close each socket when the script finishes
$allSockets = array($server);

while (true) {
    //We have to echo something to the browser or PHP won't know if the Stop button has been pressed
    //echo ' ';
    //if ( connection_aborted() ) {
        //The Stop button has been pressed, so close all our sockets and exit
        //foreach ($allSockets as $socket) socket_close($socket);
        //break;
    //}

    //socket_select() is slightly strange. You have to make a copy of the array
    // of sockets you pass to it, because it changes that array when it returns
    // and the resulting array will only contain sockets with waiting data on
    // them. $write and $except are set to NULL because we aren't interested in
    // them. The last parameter indicates that socket_select will return after
    // that many seconds if no data is receiveed in that time; this prevents the
    // script hanging forever at this point (remember, we might want to accept a
    // new connection or even exit entirely) and also pauses the script briefly
    // to prevent this tight while() loop using a lot of processor time
    $changedSockets = $allSockets;
    @socket_select($changedSockets, $write = NULL, $except = NULL, 10);

    //Now we loop over each of the sockets that socket_select() says have new
    // data on them
    foreach($changedSockets as $socket) {
        if ($socket == $server) {
            //socket_select() will include our server socket in the
            // $changedSockets array if there is an incoming connection attempt
            // on it. This will only accept one incoming connection per while()
            // loop iteration, but that shouldn't be a problem given the
            // frequency that we're iterating
            if (!($client = @socket_accept($server))) {
                socketError('socket_accept', false);
            } else {
                //Accepted incoming connection, add new client socket to our array of sockets
                @socket_set_nonblock($client);
                $allSockets[] = $client;
            }
            echo "Accepted: allSockets count = ".count($allSockets)." memory: ".memory_get_usage()."\n";
        } else {
            //Attempt to read data from this socket
            echo "socket read start\n"; //DEBUG
            $data = @socket_read($socket, 1024);
            echo "socket read end\n"; //DEBUG
            if ($data === false || $data === '') {
                //socket_read() returned FALSE, meaning that the client has
                // closed the connection. Therefore we need to remove this
                // socket from our client sockets array and close the socket
                //A potential bug in PHP means that socket_read() will return
                // an empty string instead of FALSE when the connection has
                // been closed, contrary to what the documentation states. As
                // such, we look for FALSE or an empty string (an empty string
                // for the current, buggy, behaviour, and FALSE in case it ends
                // up getting fixed at some point)
                unset($allSockets[array_search($socket, $allSockets)]);
                @socket_close($socket);
                echo "$socket closed, number left = ".count($allSockets)."\n";
            } else {
                //We got useful data from socket_read()
                echo "$socket [".count($allSockets)." - ".memory_get_usage(). "] wrote: $data\n";

                // ADD YOUR DATA HANDLER HERE
            }
        }
    }
} // end while

?>

答案 1 :(得分:0)

我有同样的问题,这就是我解决它的方法:

$result = socket_read($socket,2000);

if ($result === "") {
      // it goes in here when the socket (host) has disconnected
}
else {
     // it goes in here when the buffer is empty or the buffer has data in it
}