处理握手过程中的 websocket 发送而不丢失消息

发布于 2024-11-26 07:06:45 字数 991 浏览 2 评论 0原文

我想实现以下行为。假设客户端有一个按钮,它会触发一个通过 websocket 发送消息的函数。第一次调用此函数时,将创建一个 WebSocket 实例,然后在以后的调用中使用。

创建 WebSocket 实例是非阻塞的。构造函数立即返回一个 WebSocket 对象,在后台启动握手。连接成功会触发onopen回调。

当第二个呼叫进入并且 Websocket 仍在执行握手时(例如用户双击按钮),就会出现问题。当websocket完成握手时,所有消息都需要排队并发送。

以下代码使用 jQuery 和自定义事件来收集握手期间收到的所有消息。

var ws = null;

function sendMessage(message) {
    if (!ws) {
        ws = new WebSocket("ws://example.com");
        ws.onopen = function() {
            $(document).trigger('handshakeComplete');
        }
    }
    if (ws.readyState == WebSocket.CONNECTING) { // *
            $(document).bind('handshakeComplete', message, function(event) {
                ws.send(event.data);
            });
    } else if (ws.readyState == WebSocket.OPEN) {
        // use the persistent connection
        ws.send(message);
    }
}

星号行的条件可能会被评估为 true,此时 websocket 会进入 OPEN 状态,执行 onopen 回调,并且只有在此之后,当前消息才会添加到等待握手完成事件的队列中。这会导致消息丢失。

我想避免这种情况,并且非常感谢任何想法、意见或建议。

I'd like to achieve the following behavior. Suppose there is a button on the client side which triggers a function that sends a message via a websocket. The first time this function is called, a WebSocket instance is created and then used in the future calls.

Creating a WebSocket instance is non-blocking. The constructor immediately returns a WebSocket object, starting the handshake in the background. A successful connection triggers the onopen callback.

A problem shows up when the second call comes in and the websocket is still performing the handshake (e.g. user makes double click on the button). All the messages need to be queued and sent when the websocket completes the handshake.

The following piece of code uses jQuery and a custom event to gather all messages received during the handshake.

var ws = null;

function sendMessage(message) {
    if (!ws) {
        ws = new WebSocket("ws://example.com");
        ws.onopen = function() {
            $(document).trigger('handshakeComplete');
        }
    }
    if (ws.readyState == WebSocket.CONNECTING) { // *
            $(document).bind('handshakeComplete', message, function(event) {
                ws.send(event.data);
            });
    } else if (ws.readyState == WebSocket.OPEN) {
        // use the persistent connection
        ws.send(message);
    }
}

It is possible the condition at the starred line to be evaluated as true and in that moment the websocket passes in the OPEN state, the onopen callback is executed and only after that the current message is added in the queue waiting for the handshakeComplete event. This would result in the loss of messages.

I would like to avoid this and I would appreciate any ideas, comments or suggestions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

韶华倾负 2024-12-03 07:06:45

我认为您担心在测试(== CONNECTING)和bind()发生之间可能会触发handshakecomplete,并且握手完成的消息永远不会被发送。

理论上,如果所有存在的都是 JS,那么这将是错误的,因为在当前代码完成之前该事件不会触发。然而,实际上,事件可能在后台的另一个线程上生成,并且仅在达到稳定状态后在前台运行。

答案是不要将消息嵌入握手事件处理程序中。我建议将消息​​添加到队列/数组中,并在 onopen 处理程序中处理该数组。 onopen 事件可以在我们执行时触发(排队),但它不会运行,直到我们达到稳定状态(所有消息都在队列/数组中)。

I think you're worried that handshakecomplete could fire between the test (== CONNECTING) and when the bind() happens, and the message for the handshakecomplete would never be sent.

In theory if all that existed was JS, this would be wrong, since the event wouldn't fire until the current code finished. However, in reality the event may be generated on another thread in the background, and merely be run in the foreground after we reach a stable state.

The answer is to not embed the message in the handshake event handler. I suggest adding the message to a queue/array, and in the onopen handler process the array. The onopen event can fire (get queued) while we're executing, but it won't run until we hit a stable state (where all the messages are in the queue/array).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文