Простой сервер websocket в PHP

Я разрабатываю простой сервер websocket в PHP. Я знаю, что существует довольно много существующих реализаций, но я хочу сделать так, чтобы лучше изучить протокол. Я сумел сделать handshaking тонкой и мои клиенты соединяются к серверу. Мне также удалось декодировать данные от клиента, но у меня проблемы с отправкой сообщений. Клиент отключается, когда получает мой ответ. Firefox говорит The connection to ws://localhost:12345/ was interrupted while the page was loading..

Я использовал этот ответ в качестве руководства.

Вот мой код для обертывания данных:

private function wrap($msg = ""){
    $length = strlen($msg);
    $this->log("wrapping (" . $length . " bytes): " . $msg);

    $bytesFormatted = chr(129);
    if($length <= 125){
        $bytesFormatted .= chr($length);
    } else if($length >= 126 && $length <= 65535) {
        $bytesFormatted .= chr(126);
        $bytesFormatted .= chr(( $length  >> 8 ) & 255);
        $bytesFormatted .= chr(( $length       ) & 255);
    } else {
        $bytesFormatted .= chr(127);
        $bytesFormatted .= chr(( $length >> 56 ) & 255);
        $bytesFormatted .= chr(( $length >> 48 ) & 255);
        $bytesFormatted .= chr(( $length >> 40 ) & 255);
        $bytesFormatted .= chr(( $length >> 32 ) & 255);
        $bytesFormatted .= chr(( $length >> 24 ) & 255);
        $bytesFormatted .= chr(( $length >> 16 ) & 255);
        $bytesFormatted .= chr(( $length >>  8 ) & 255);
        $bytesFormatted .= chr(( $length       ) & 255);
    }

    $bytesFormatted .= $msg;
    $this->log("wrapped (" . strlen($bytesFormatted) . " bytes): " . $bytesFormatted);
    return $bytesFormatted;
}

UPDATE: я попробовал его с Chrome, и я получил следующую ошибку, напечатанную на консоли: A server must not mask any frames that it sends to the client.

Я помещаю на сервер некоторые распечатки на консоли. Это базовый сервер эха. Я пытаюсь использовать aaaa. Таким образом, фактическое обернутое сообщение должно быть 6 байтов. Правильно?

enter image description here

Chrome печатает указанную выше ошибку. Также обратите внимание, что после переноса сообщения я просто пишу его в сокет:

$sent = socket_write($client, $bytesFormatted, strlen($bytesFormatted));
$this->say("! " . $sent);

Он печатает 6 значений, на самом деле 6 байтов записываются в провод.

Если я попытаюсь с помощью aaa, Chrome не печатает ошибку, но также не вызывает мой обработчик onmessage. Он зависает, как ожидая большего количества данных.

Любая помощь высоко ценится. Спасибо.

Ответы

Ответ 1

У меня была та же проблема: для некоторых сообщений, отправленных с сервера, в браузере не было ответа, поскольку некоторая ошибка "Сервер не должен маскировать какие-либо фреймы..." был отображен, хотя я не добавлял никакой маски, Причина была в рукопожатии. Рукопожатие было:

"HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
...
"WebSocket-Location: ws://{$host}{$resource}\r\n\r\n" . chr(0)

Этот chr (0) был причиной, после того как я удалил все, все работает.

Ответ 2

Когда я писал свои классы websocket, у меня была такая же проблема. В моем случае я использовал выходную буферизацию, чтобы определить, что я что-то повторил, прежде чем отправил ответ. Можете попробовать это и посмотреть, если это проблема.