JavaScript WebSocket 非以 null 结尾的字符串

JavaScript WebSocket non-null-terminated strings

本文关键字:字符串 结尾 null WebSocket 非以 JavaScript      更新时间:2023-09-26

我有一个很奇怪的问题。我有一个开放的WebSocket,通信工作正常。我还有窗口的 onblur 和 onfocus 事件,它们通过所述连接通知服务器。但是,在这种情况下,我收到的字符串是非 null 终止的。否则,即使发送与在各自的模糊/焦点事件上发送的相同字符串,通信也绝对无可挑剔。为什么会这样,如何解决?

下面是一些代码:

$(document).ready(function(){
    initializeEverything();
    window.onblur = function(){ notifyFocusChange(false); };
    window.onfocus = function(){ notifyFocusChange(true); };
});
function notifyFocusChange(present){
    if(present){
        webSocket.send('presence:present');
    }else{
        webSocket.send('presence:absent');
    }
}

下面是我在事件触发时收到的非 null 终止字符串的示例:

presence:absentÏ┘ê÷/à°äJ÷ÝÿLÓ▓ùM÷Ýÿ[

编辑:有人建议这可能是服务器错误,所以这里是解码传入消息的代码:

private function decode($payload) {
    $length = ord($payload[1]) & 127;
    if ($length == 126) {
        $masks = substr($payload, 4, 4);
        $data = substr($payload, 8);
    } elseif ($length == 127) {
        $masks = substr($payload, 10, 4);
        $data = substr($payload, 14);
    } else {
        $masks = substr($payload, 2, 4);
        $data = substr($payload, 6);
    }
    $text = '';
    for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i % 4];
    }
    return $text;
}

编辑:它只发生在Chrome中。我在Firefox上检查了它,它使用相同的WebSocket协议,那里一切正常。

onblur和onfocus事件可能连续发生几次。这意味着 websocket.send 调用也会被快速连续多次快速调用。

如果多个发送调用发生得足够近,那么您很有可能在服务器上的一次读取中收到多个帧,我相信这就是您所看到的。换句话说,有效负载中的"垃圾"实际上是一个或多个后续 WebSocket 帧。

在同一个 Javascript 上下文中执行两个单独的发送时,您可以手动复制问题:

function do_test () {
    ws.send("data1");
    ws.send("data2");
}

这将发送两个足够接近的 WebSocket 帧,以便服务器可能会一次从套接字读取它们。

为了正确处理帧,您必须解析有效负载长度字段,并且仅读取/取消屏蔽指定数量的有效负载数据。剩余的任何内容都需要排队作为新帧的开头。

此外,不仅可以从套接字读取返回多个 Websocket 帧,而且您不能依赖将帧作为整个帧读取:您可以在一次读取中读取一半的帧,在下一帧中读取另一半。换句话说,第一次从套接字读取时,您可能会得到 3 个完整的 websocket 帧加上第 4 帧的 1 个字节,然后在下一次从套接字读取时,您将获得第 4 帧的其余部分。

这通常可以这样总结:WebSockets是基于消息的传输协议,而TCP套接字是一种流协议。由于 WebSocket 在 TCP 上分层,这意味着 WebSocket 服务器(和客户端)必须执行转换以向应用程序呈现整个消息,即使基础传输不是基于消息的。