我的节点服务器应用程序正在使用ws WebSocket库:
socket.send(data, err => {
if (err == null) {...success...}
else {...failure...}
客户端也使用ws:
侦听消息ws.on('message', message => ...handler...);
我正在寻找一个错误,有时,如果客户端的网络连接丢失(例如我关闭wifi),那么看起来服务器报告消息已成功发送但客户端的处理程序从未被调用过。< / p>
问题:这可能吗?这确实是'ws'WebSocket库的预期失败模式之一吗? socket.send()
的成功实际证明了什么?
(我知道所有的网络协议都有一些漏洞存在于某个地方。我正试着把手指放在ws库的精确窗口所在的地方,这样我就能在它上面建立正确的语义。我的避风港还没有从文档中找到ws确切的窗口。)
可能:一旦将消息放入其传出的TCP缓冲区中,也许socket.send
会报告成功。但是如果网络在退出TCP缓冲区之前出现故障,那么该消息将永远丢失。
MAYBE:也许socket.send
报告成功,一旦它将消息传递到收件人的TCP消息队列并收到TCP ACK确认它已经被传递,但是如果客户端的网络在处理程序被丢失之前关闭然后调用该消息将永远丢失。
答案 0 :(得分:3)
了解客户端收到webSocket消息的唯一方法是让客户端将自己的自定义消息发送回服务器以指示您收到它并让您在服务器上等待该消息。
这是唯一可以保证的端到端测试。其他任何东西都依赖于链中较低的其他东西,这并不代表客户实际接收和处理的消息。因为您想知道应用程序级别已收到并处理了该消息,您必须在应用程序级别回复以合法地知道应用程序级别已收到它。
仅供参考,socket.io(建立在webSocket之上)将为您完成此操作。如果您传递callback to socket.emit()
in socket.io,它将从客户端请求回复,并且当调用该回调时,您将知道它实际上已收到。您可以在webSocket中自己实现它或使用socket.io,它具有内置的功能。
我实际上并不知道websocket.send()
决定成功的级别,但重点是它的级别低于应用程序级别(正如您在问题中已经概述的那样),所以如果如果您希望应用程序级别确定,则不能仅依靠其功能 - 您必须添加额外的应用程序级别确认或使用已构建到socket.io中的那个。
答案 1 :(得分:2)
根据the documentation,在成功发送消息后调用回调时没有错误。我怀疑(但我没有仔细观察)这意味着它已成功传递到操作系统(放置在发送队列中)。我很确定不意味着客户端发送了TCP ACK。
TCP连接的“问题”是,由于它们的弹性,可能需要很长时间才能通知服务器与客户端的连接已丢失(因为它可能实际上并未丢失永久性),并且在连接之上没有某种确认层,您将永远不知道消息是否实际上已经传递给客户端。
ws
文档提供了一些有关如何检测断开连接的示例代码:https://github.com/websockets/ws#how-to-detect-and-close-broken-connections
TL; DR:定期向每个客户端发送“ping”消息,并期望客户端在特定时间范围内返回“pong”消息。