клиент HTML5 для php-сервера и WebSocket HTML5

#javascript #php #sockets #websocket

Вопрос:

я пытаюсь подключить клиент [WebSocket] к сокету PHP-сервера, мой серверный сокет примет сокет от клиента и получит заголовки запросов,

получив запрос, я отправил ответное рукопожатие [ответ] Но статус WebSocket [клиент] находится в ожидании и никогда не получит ответа

Код JS:

       const URL = "ws://localhost:8050";
      var socket = new WebSocket(URL);
    
      socket.onopen = function() {
        console.log("Socket is openned!");
      }
      socket.onmessage = function() {
        console.log("new message!");
      }
 

и мой сокет PHP-сервера:

 $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);


    if (socket_bind($this->socket, self::ADDRESS, self::PORT) === false) {
      throw new Exception("Could not bind socket at address ${self::ADDRESS}, port ${self::PORT}");
    }


    if (socket_listen($this->socket) === false) {
      throw new Exception("Could not listen!!");
    }

    $running = true;
    $clients = [];
    while ($running) {

      if (count($clients) < 2) {
        $accept = socket_accept($this->socket);
        // handshake
        $this->handshake($accept);
        $clients[] = $accept;

        sleep(2);
        continue;
      }
    }
 

функция рукопожатия:

   private function handshake($client) {

    if ($client instanceof Socket || is_resource($client)) {
      echo "== Client is Vaild ==n";
    }

    // client sent the Request
    $read = socket_read($client, 2048);
    if ($read === false) {
      throw new Exception("Could not Read!!");
    }

    // headers
    if (preg_match("/Sec-WebSocket-Key: (.*)/", $read, $matches)){ 

      $key = base64_encode(hash("sha1",$matches[1]."258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); 

      $response_header = "HTTP/1.1 101 Switching Protocolsrn".
      "Upgrade: websocketrn".
      "Connection: Upgradern".
      "Sec-WebSocket-Accept: $keyrn";

      // send the response
      $bytes_sent = socket_write($client, $response_header, strlen($response_header));

      if ($bytes_sent === false) {
        echo "n====== Cannot send the handshake ==========n";
      } elseif ($bytes_sent > 0) {
        // ------- sent around 155 bytes ----------- //
        echo "n====== handshake has been sent [". $bytes_sent ."bytes] ==========n";
      }


    }
  }
 

После отправки ответа клиент все еще находится в состоянии ожидания,
а соединение не открыто.

Спасибо.

Запрос От Клиента:

 GET / HTTP/1.1
Host: localhost:8050
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36
Upgrade: websocket
Origin: http://localhost
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,ar;q=0.8
Cookie: _ga=GA1.1.213058296.1602471332; __atuvc=1|52,1|3
Sec-WebSocket-Key: UmjWLRlhTXqM1rF6kSaVhQ==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
 

то, что я пытаюсь, — это отправить ответ обратно:

 HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: NmQwYjVlY2VhMTQzMzUyYjFiNWMwZmU4Y2E3NmFjZTc4ZDc4N2I2Yw==
 

Обновить:

  • Я исправил ключ Sec-WebSocket-Accept, используя sha1(…, двоичный код = true) перед base64.
  • Завершите мой ответ, который я добавил rn , чтобы завершить ответ заголовка.

Теперь я получаю сообщение об ошибке: подключение к WebSocket http://host:port потерпел неудачу.

Комментарии:

1. После переключения протокола браузер открывает новое TCP-соединение на определенном порту, но кажется, что ваш сервер там даже не прослушивает. Я не уверен в конфигурации вашей сети , но я бы предложил использовать решения сокетов на основе NODEJS, а не создавать это с нуля с помощью PHP. Возможно, ваша проблема заключается в APACHE/NGINX, который должен указывать конкретные заголовки перед подключением к WebSocket(обновление и подключение)

2. Спасибо за ваш комментарий, я знаю об узле js [socket.io ..и т. Д.] или с помощью [Firebase..и т. Д.], Но я хочу проверить свой уровень и бросить вызов самому себе..

Ответ №1:

Все сделано, проблема была Sec-WebSocket-Accept ключевой, ее нужно было решить trim(key)