Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple websocket server in PHP

I am developing a simple websocket server in PHP. I know there are quite a few existing implementations but I want to make my own so to learn the protocol better. I managed to do the handshaking fine and my clients connect to the server. I also managed to decode the data from the client but I have problems sending back messages. The client disconnects when it receives my response. Firefox says The connection to ws://localhost:12345/ was interrupted while the page was loading..

I used this answer as a guide.

Here is my code for wrapping the data:

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: I tried it with Chrome and I got the following error, printed in the console: A server must not mask any frames that it sends to the client.

I put some console printouts on the server. It is a basic echo server. I try with aaaa. So the actual wrapped message must be 6 bytes. Right?

enter image description here

Chrome prints the above error. Note also that after wrapping the message I simply write it to the socket:

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

It prints 6 meaning 6 bytes are actually written to the wire.

If I try with aaa, Chrome doesn't print the error but doesn't call my onmessage handler either. It hangs as if waiting for more data.

Any help highly appreciated. Thanks.

like image 932
Martin Dimitrov Avatar asked Oct 29 '12 11:10

Martin Dimitrov


People also ask

Can I use WebSockets with PHP?

Socket as the generator source The thing is, PHP has everything it needs to work with WebSockets.

How configure WebSocket in PHP?

To implement WebSocket with PHP, you have to install an additional module like Swoole. You have more than one module that allows you to implement WebSocket service in PHP, in this tutorial I'm going to use Open Swoole implementation by SwooleLabs considering that Open Swoole includes support for WebSocket.

How do I create a WebSocket server?

Creating a WebSocket objectThe URL to which to connect; this should be the URL to which the WebSocket server will respond. This should use the URL scheme wss:// , although some software may allow you to use the insecure ws:// for local connections. Either a single protocol string or an array of protocol strings.

How do I run a WebSocket server?

To open a websocket connection, we need to create new WebSocket using the special protocol ws in the url: let socket = new WebSocket("ws://javascript.info"); There's also encrypted wss:// protocol. It's like HTTPS for websockets.


1 Answers

I had the same problem: for some messages sent from the server there was no response in the browser, for some the error "A server must not mask any frames ..." was displayed, though I did not add any mask. The reason was in the handshake sent. The handshake was:

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

That chr(0) was the reason, after I removed it everything works.

like image 147
Alan Smith Avatar answered Sep 21 '22 02:09

Alan Smith