douyanning3724 2019-02-11 11:20
浏览 221

Websocket服务器不允许来自客户端的新连接,卡在socket_read上(没有错误)

I have websocket server written in native php. I run the server in linux's screen.

It works fine. client can connect to the webserver. but after a few days (not sure how many days, happen randomly), the websocket are not accepting new connection anymore.

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.'
');
    }

    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.'
');
            }

            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.'
');
            }

            /**
            * 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.'
');
            }

            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.'
');
            }
            unset($clientSockets[$socket_index]);
            if(isset($socketLists[$socket_list_index])){
                unset($socketLists[$socket_list_index]);
            }
        }
    }
}

It always stop at error_log('Websocket new connection before read header');

I expect if there is an error, it will show here error_log('Could not read on new_client_socket: ['.$error_code.'] '.$error_msg.' ');

But no error came out. It just stuck there.

If i try to connect to the websocket, i check netstat -tcp in server, it shows state Established.

the status:- tcp 0 0 roomie-devel:cslistener internettl.org:51715 ESTABLISHED 17556/php

please someone help me, is there any settings in linux that i need to change?

i try socket_close, but it return error:- error disconnect socket_close: [104] Connection reset by peer

there's also error in socket_getpeername() and another socket_close() error:- 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

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

based on my research, to close tcp connection, both end need to send close connection request. but you cannot called the socket_close if client is unexpectedly close their connection (for eg: they force shutdown their computer). how do i properly close connection for this situation? do i need to set anything in linux to close any socket not properly close?

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥20 usb设备兼容性问题
    • ¥15 错误(10048): “调用exui内部功能”库命令的参数“参数4”不能接受空数据。怎么解决啊
    • ¥15 安装svn网络有问题怎么办
    • ¥15 Python爬取指定微博话题下的内容,保存为txt
    • ¥15 vue2登录调用后端接口如何实现
    • ¥65 永磁型步进电机PID算法
    • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
    • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
    • ¥15 如何处理复杂数据表格的除法运算
    • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)