使用PHP编写简单的WebSocket服务器

16

我正在使用PHP开发一个简单的WebSocket服务器。我知道已经有很多现成的实现,但我想自己编写以更好地学习协议。我成功完成了握手,并让客户端连接到了服务器。我也能够解码来自客户端的数据,但在发送回消息时出现了问题。当客户端收到我的响应时,它会断开连接。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;
}

更新:我尝试了使用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处理程序。 它就像在等待更多数据一样挂起。

非常感谢任何帮助。谢谢。


你是否使用过Wireshark来检查通过网络发送的字节与代码中生成的内容是否匹配?并且没有其他代码发送额外的数据,可能会被解释为消息的开头? - simonc
为什么要使用chr函数而不是pack函数? - Dave Kok
@DaveKok chr(129) 返回一个字节。pack('c', 129) 也返回一个字节。请参见 http://codepad.org/N3KWIXTq - Martin Dimitrov
@Stan 嗯,我正在遵循问题中链接的建议,作者说没有必要掩盖输出。浏览器的输入始终是掩盖的,但服务器的输出不是。此外,在包装后没有太多的代码。我只是用 socket_write 写入数据。它的返回值告诉我所有字节都已正确发送到客户端。 - Martin Dimitrov
然而,错误似乎出现在代码的其他部分,而不是所呈现的部分。根据您提到的错误消息,看起来在握手之后发送了一些过多的数据。 - Stan
显示剩余6条评论
2个回答

4

我有同样的问题:从服务器发送的一些消息在浏览器中没有响应,而另一些消息会显示错误“服务器不得掩盖任何帧...”,尽管我没有添加任何掩盖。

原因在于发送的握手。

握手如下:

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

chr(0)就是问题所在,将它删除后一切正常。


0
当我编写我的WebSocket类时,我遇到了同样的问题。 在我的情况下,我使用输出缓冲区来确定在发送回复之前是否已经输出了某些内容。 可以尝试这样做,看看是否是问题所在。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接