使用原始 WebSocket 时如何知道消息是不是已成功发送?

Posted

技术标签:

【中文标题】使用原始 WebSocket 时如何知道消息是不是已成功发送?【英文标题】:How do I know if an message has been sent successfully when using raw WebSocket?使用原始 WebSocket 时如何知道消息是否已成功发送? 【发布时间】:2018-01-25 04:34:17 【问题描述】:

与接受可选的ack 回调的websocket/ws 不同,原始WebSocket.prototype.send 只接受一条消息。

【问题讨论】:

【参考方案1】:

请注意 sent != received...我假设您想确保消息已收到

实现ACK。这非常简单,而且这是我知道的确保收到消息的唯一方法。

一个足够好的方法是在客户端附加一个消息 ID 并将该 ID 作为消息的一部分发送(即在 JSON 中作为msgID)。我使用计时器 ID,因为我在 ACK 到达时取消了计时器,这是保留计时器数据的好方法。

当服务器识别出msgID 时,它应该在处理消息的其余部分(即"event":"ACK", "data":m["msgID"] 的 JSON)之前自动发送具有相同消息 ID 的 ACK。

如果您使用二进制数据,您可以简单地在每条消息的开头附加一个固定大小的 ID(例如 8 个字节),或者为一个动态大小的 ID 附加一个长度指示符。

编辑反思雷米的评论:

是的,使用超时 ID 可能严重依赖 ID“池”的实现方式。

更安全的设计可能更愿意通过使用计数器或其他方法来避免假设。

但是,还应注意,在我测试此方法的所有浏览器中,超时 ID 始终是唯一的。

在Mozilla Developer Documentation Site 上,它声明:

保证超时 ID 永远不会被同一对象(窗口或工作器)上的后续调用 setTimeout() 或 setInterval() 重用。但是,不同的对象使用不同的 ID 池。

我认为这个假设对于所有浏览器来说都是正确的(受制于 ID 类型溢出并将自身重置为零)。

【讨论】:

"我使用计时器 ID,因为我在 ACK 到达时取消计时器" - 我不会使用这样的计时器 ID。想想如果 ACK 被延迟会发生什么,所以你在一段时间后终止计时器并在稍后的消息上启动一个新的计时器,系统决定重用旧的计时器 ID,然后旧的 ACK 终于到达。使用滚动数字作为消息 ID 并使用关联的计时器跟踪它们并不难。获取 ACK,找到消息 ID,杀死相关的计时器。它们不必是相同的 ID。 @RemyLebeau - 这是一个很好的观点。但是,我不确定在实践中如何应用。我在 Chrome、Safari 和 FireFox 上进行了测试——它们都没有回收计时器句柄......我认为这些句柄并不直接反映文件描述符,而是使用内部设计和计数器,直到它的类型溢出(这是一个很多个计时器)...我测试使用:existing = ; function my_func(e) id = window.setTimeout(my_func, 1000); console.log(id); if(existing[id]) window.clearTimeout(id); console.log("EXISTING", id);; existing[id] = 1; my_func(0);,我使用了不同的间隔值。 @RemyLebeau 你能写下你的答案版本吗?像我们这样的初学者向您学习会很有帮助。

以上是关于使用原始 WebSocket 时如何知道消息是不是已成功发送?的主要内容,如果未能解决你的问题,请参考以下文章

播放框架1.2.5 Websocket

如何使用 websocket 检查消息是不是真的在 Netty 中传递?

C# - Websocket - 将消息发送回客户端

java websocket上线后如何发送离线用户的消息?

如何使用 WebSocket 发送定期消息?

如何从 websocket 端点外部发出 websocket 消息?