首页 > 解决方案 > Websocket 服务器不允许来自客户端的新连接,卡在 socket_read(没有错误)

问题描述

我有用本机 php 编写的 websocket 服务器。我在 linux 的屏幕上运行服务器。

它工作正常。客户端可以连接到网络服务器。但几天后(不确定多少天,随机发生),websocket 不再接受新连接。

set_time_limit(0);

if(!($socket = socket_create(AF_INET, SOCK_STREAM, 0))){
    $error_code = socket_last_error();
    $error_msg = socket_strerror($error_code);
    die();
}

if(!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)){
    $error_code = socket_last_error();
    $error_msg = socket_strerror($error_code);
    die();
}

if(!socket_bind($socket, 0, $port)){
    $error_code = socket_last_error();
    $error_msg = socket_strerror($error_code);
    die();
}

if(!socket_listen($socket))
{
    $error_code = socket_last_error();
    $error_msg = socket_strerror($error_code);
    die();
}

/**
 * array of client sockets
 **/
$clientSockets = array($socket);
$socketLists = array();

$write = null;
$except = null;
$header = array();

/**
 * start endless loop, so that our script doesn't stop
 **/
while (true) {
    /**
    * array of sockets to read
    * !get from clientSockets array
    **/
    $readSockets = $clientSockets;

    /**
    * now call select - blocking call
    **/
    if(socket_select($readSockets , $write , $except , 0, 10) === false)
    {
        $error_code = socket_last_error();
        $error_msg = socket_strerror($error_code);

        error_log('Could not listen on socket: ['.$error_code.'] '.$error_msg.'\n');
    }

    if(in_array($socket, $readSockets)){
        /**
        * Accept new client socket
        **/
        if(($new_client_socket = socket_accept($socket)) !== false){
            error_log('Websocket has new connection');
            /**
            * Add new client socket to client socket array
            **/
            $clientSockets[] = $new_client_socket;

            /**
            * read data sent by the socket buffer(65536, 65536)
            **/
            error_log('Websocket new connection before read header');
            if(!($header = socket_read($new_client_socket, 65536))){
                $error_code = socket_last_error();
                $error_msg = socket_strerror($error_code);

                error_log('Could not read on new_client_socket: ['.$error_code.'] '.$error_msg.'\n');
            }

            error_log('Websocket new connection after read header => '.json_encode($header));

            $datas = json_decode($header);

            if ((isset($datas->type) && $datas->type == "server") || (isset($datas->type) && $datas->type == "cec")) { 
                $newDatas = json_decode($datas->data);
                $searchIndex = strtolower($newDatas->ip_address) . '-' . strtolower($newDatas->mac_address);
                unset($datas->type);
                $response = mask(json_encode($datas));

                checkSocketAndSendMessage($clientSockets, $socketLists, $searchIndex, $response);
            }else{
                performHandshaking($header, $new_client_socket, $host, $port);
            }

            /**
            * make room for new socket
            **/
            $found_socket = array_search($socket, readSockets);
            unset($readSockets[$found_socket]);
        }else{
            $error_code = socket_last_error();
            $error_msg = socket_strerror($error_code);
            // die();
        }
    }


    foreach ($readSockets as $readSocket) {
        $buf = @socket_read($readSocket, 65536, PHP_NORMAL_READ);

        if(strlen($buf) < 1){
            $socket_index = array_search($readSocket, $clientSockets);

            $socket_list_index = '';
            foreach($socketLists as $key => $socketList){
                if($readSocket == $socketList['index']){
                    $socket_list_index = $key;
                }
            }

            if(!socket_getpeername($readSocket, $ip)){
                $error_code = socket_last_error();
                $error_msg = socket_strerror($error_code);

                error_log('error disconnect socket_getpeername: ['.$error_code.'] '.$error_msg.'\n');
            }

            /**
            * Added to try cater
            * CLOSE_WAIT problem
            **/
            $linger     = array ('l_linger' => 0, 'l_onoff' => 1);
            if(!socket_set_option($clientSockets[$socket_index], SOL_SOCKET, SO_LINGER, $linger)){
                $error_code = socket_last_error();
                $error_msg = socket_strerror($error_code);

                error_log('error disconnect socket_set_option: ['.$error_code.'] '.$error_msg.'\n');
            }

            if(!socket_close($clientSockets[$socket_index])){
                $error_code = socket_last_error();
                $error_msg = socket_strerror($error_code);

                error_log('error disconnect socket_close: ['.$error_code.'] '.$error_msg.'\n');
            }
            unset($clientSockets[$socket_index]);
            if(isset($socketLists[$socket_list_index])){
                unset($socketLists[$socket_list_index]);
            }
        }
    }
}

它总是停在error_log('Websocket new connection before read header');

我希望如果有错误,它会显示在这里error_log('Could not read on new_client_socket: ['.$error_code.'] '.$error_msg.'\n');

但是没有出现错误。它只是卡在那里。

如果我尝试连接到 websocket,我检查netstat -tcp服务器,它显示状态Established

状态:- tcp 0 0 roomie-devel:cslistener internettl.org:51715 ESTABLISHED 17556/php

请有人帮助我,我需要更改linux中的任何设置吗?

我尝试socket_close,但它返回错误: - error disconnect socket_close: [104] Connection reset by peer\n

socket_getpeername() 和另一个 socket_close() 错误中也有错误:- PHP Warning: socket_getpeername(): unable to retrieve peer name [107]: Transport endpoint is not connected in /var/www/html/webSocket/webSocket.php on line 296

error disconnect socket_getpeername: [107] Transport endpoint is not connected\n

error disconnect socket_close: [107] Transport endpoint is not connected\n

根据我的研究,要关闭 tcp 连接,两端都需要发送关闭连接请求。但是如果客户端意外关闭他们的连接(例如:他们强制关闭他们的计算机),你不能调用 socket_close。对于这种情况,我该如何正确关闭连接?我是否需要在 linux 中设置任何内容来关闭任何未正确关闭的套接字?

标签: phplinuxsocketstcpwebsocket

解决方案


推荐阅读