1

我正在使用该ws模块在 NodeJS 上实现 WebSockets 服务器。服务器应每分钟向所有客户端发送一次更新。我已经实现了这个,但我对它在客户端连接可能停止的情况下的功能有些担心。

我担心当与客户端的连接变为非活动状态时会发生什么,例如由于网络连接以不发送 TCP RST 或 FIN 的方式中断。

我有点惊讶于方法中没有使用关键字send()调用该方法。该方法是否只是将所有要发送的数据排队?如果套接字缓冲区已满,会以一种导致其他客户端饥饿的方式阻塞,而不是被阻塞的客户端怎么办?awaitasyncsend()send()

如果send()从不阻塞,如果数据排队,排队,排队......会发生什么?它可以使用不断增加的无限内存吗?

理想情况下,如果最后一次更新尚未完全发送,我想省略发送每分钟一次的更新。我可以通过ws模块实现这一点吗?

4

1 回答 1

3

我担心当与客户端的连接变为非活动状态时会发生什么,例如由于网络连接以不发送 TCP RST 或 FIN 的方式中断。

如果连接以这种方式丢失(可能是由于客户端系统被关闭或物理断开),那么服务器上的 TCP 将检测到断开的连接,因为它不会收到已发送数据的确认。TCP 可能需要几分钟才能放弃,但在这种情况下,这听起来不是什么大问题。

最坏的情况是客户端系统保持连接但客户端进程停止从连接中读取数据。在这种情况下,发送的数据将在客户端累积,直到客户端的套接字接收缓冲区填满,然后发送的数据将在服务器累积——首先在内核套接字发送缓冲区中,然后在服务器进程内存中。

我有点惊讶的是,在异步方法中没有使用 await 关键字调用 send() 方法。

ws比 async/await 和 promise 早了几年。我想 API 最终会被改造,但它还没有发生。

send() 方法是否只是将所有要发送的数据排队?如果套接字缓冲区已满,send() 会以一种导致其他客户端饥饿的方式阻塞,而不是被阻塞的客户端怎么办?

WebSocket.send最终调用内置Net模块的Socket.write. (有关该调用,请参阅 https://github.com/websockets/ws/blob/master/lib/sender.js 底部的函数sendFrame,并参阅https://nodejs.org/docs/latest-v8.x/ api/net.html#net_class_net_socket用于类的文档。)Socket

Socket.write如果内核不能立即接受数据,将在用户进程中缓冲数据。数据是单独缓冲的Socket,因此通常这种缓冲不会影响Socket连接到其他客户端的其他 s 上的传输。Socket但是,缓冲的数据量没有限制。在极端情况下,一个Socket缓冲的数据可能会消耗所有服务器进程的内存,并且由此产生的服务器崩溃会干扰向所有客户端的数据传递。

有几种方法可以避免这个问题。浮现在脑海中的两种简单方法是:

  • 为调用提供完成回调参数send。该回调将传递给Socket.write调用,当所有write数据都写入内核时,调用将触发回调。如果您的服务器在回调触发之前不向该客户端发送更多数据,则该连接在用户空间中缓冲的数据量将被限制为接近最近的send. (它不会精确到那个大小,因为缓冲的数据将包括 WebSocket 框架,加上 SSL 框架和填充,如果你的连接是加密的,在传递给的原始数据之上send。)或者

  • 在准备该连接上的数据之前检查bufferSize连接的属性。 指示当前在用户空间中为该 Socket 缓冲的数据量。如果它不为零,请跳过该客户端的 。SocketsendbufferSizesend

于 2019-03-16T04:47:41.253 回答