2

サーバーとして次のwebsocketphpクラスを使用しています:PHPWebSocket。それは私が望むことができたすべての方法でうまく機能しますが、私は少し問題に遭遇しました。

接続されているクライアント(歩き回ることができます)の位置を0.3秒ごとに更新したいと思います。whileループを探してそこにハートビートイベントを追加するのは簡単なことだと思いましたが、ここでは注意が必要です。

    // server state functions
function wsStartServer($host, $port) {
    if (isset($this->wsRead[0])) return false;

    if (!$this->wsRead[0] = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) {
        return false;
    }
    if (!socket_set_option($this->wsRead[0], SOL_SOCKET, SO_REUSEADDR, 1)) {
        socket_close($this->wsRead[0]);
        return false;
    }
    if (!socket_bind($this->wsRead[0], $host, $port)) {
        socket_close($this->wsRead[0]);
        return false;
    }
    if (!socket_listen($this->wsRead[0], 10)) {
        socket_close($this->wsRead[0]);
        return false;
    }

    $this->log("Server starting");

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

    $nextPingCheck = time() + 1;
    while (isset($this->wsRead[0])) {

        $changed = $this->wsRead;
        $result = socket_select($changed, $write, $except, 1);
                     **beat()**
        if ($result === false) {
            socket_close($this->wsRead[0]);
            return false;
        }
        elseif ($result > 0) {
            foreach ($changed as $clientID => $socket) {
                if ($clientID != 0) {
                    // client socket changed
                    $buffer = '';
                    $bytes = @socket_recv($socket, $buffer, 4096, 0);

                    if ($bytes === false) {
                        // error on recv, remove client socket (will check to send close frame)
                        $this->wsSendClientClose($clientID, self::WS_STATUS_PROTOCOL_ERROR);
                    }
                    elseif ($bytes > 0) {
                        // process handshake or frame(s)
                        if (!$this->wsProcessClient($clientID, $buffer, $bytes)) {
                            $this->wsSendClientClose($clientID, self::WS_STATUS_PROTOCOL_ERROR);
                        }
                    }
                    else {
                        // 0 bytes received from client, meaning the client closed the TCP connection
                        $this->wsRemoveClient($clientID);
                    }
                }
                else {
                    // listen socket changed
                    $client = socket_accept($this->wsRead[0]);
                    if ($client !== false) {
                        // fetch client IP as integer
                        $clientIP = '';
                        $result = socket_getpeername($client, $clientIP);
                        $clientIP = ip2long($clientIP);

                        if ($result !== false && $this->wsClientCount < self::WS_MAX_CLIENTS && (!isset($this->wsClientIPCount[$clientIP]) || $this->wsClientIPCount[$clientIP] < self::WS_MAX_CLIENTS_PER_IP)) {
                            $this->wsAddClient($client, $clientIP);
                        }
                        else {
                            socket_close($client);
                        }
                    }
                }
            }
        }

        if (time() >= $nextPingCheck) {
            $this->wsCheckIdleClients();
            $nextPingCheck = time() + 1;
        }
    }

    return true; // returned when wsStopServer() is called
}

私には、1秒に1回だけ実行する必要があるという特定のタイマーはないように見えますが、実際にはあります。while(isset($ this-> wsRead [0])){の直後にハートビート呼び出しを行っても、pingチェックについては話していません。トリガーは1秒に1回だけで、完全に困惑しています。

私は間違った場所を見ていますか?このwhileループを遅くするPHPのWebSocket実装について何かありますか?

4

1 に答える 1

1

socket_select呼び出しで1秒のタイムアウトがあります。これは、おそらく遅延が発生する場所です。その呼び出しを非ブロッキングにしたい場合は、そのタイムアウトにゼロを渡すことができます。

于 2013-01-25T14:45:32.007 に答える