我担心当与客户端的连接变为非活动状态时会发生什么,例如由于网络连接以不发送 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 缓冲的数据量。如果它不为零,请跳过该客户端的 。Socket
send
bufferSize
send