我正在使用ws
模块在NodeJS上实现WebSockets服务器。服务器应每分钟向所有客户端发送一次更新。我已经实现了此功能,但是在客户端连接可能停顿的情况下,我对其功能有些担心。
我担心当与客户端的连接变为非活动状态时会发生什么情况,例如由于网络连接中断而不发送TCP RST或FIN。
对于send()
方法中未使用await
关键字调用async
方法,我感到有些惊讶。 send()
方法是否只是将所有要发送的数据排队?如果套接字缓冲区已满,send()
会以某种方式引起阻塞,而不是阻塞其他客户端吗?
如果send()
从不阻塞,那么如果数据排队,排队又排队……会发生什么?它可以使用不断增长的无限内存吗?
理想情况下,如果最近一次更新没有完全发送,我想忽略每分钟发送一次更新。我可以使用ws
模块来实现吗?
答案 0 :(得分:1)
我担心当与客户端建立连接时会发生什么 处于非活动状态,例如由于网络连接中断 不发送TCP RST或FIN。
如果以这种方式断开连接(可能是由于客户端系统关闭或物理断开了连接),则服务器上的TCP将检测到断开的连接,因为它将不接收已发送数据的确认。 TCP可能要花几分钟的时间,但是在这种情况下,这听起来并不是什么大问题。
最坏的情况是客户端系统保持连接状态,但客户端进程停止从连接中读取数据。在这种情况下,发送的数据将在客户端累积,直到客户端的套接字接收缓冲区填满为止,然后发送的数据将在服务器上累积-首先在内核套接字发送缓冲区中,然后在服务器进程内存中。
令我有些惊讶的是,send()方法没有与 异步方法中的await关键字。
ws
早于async / await和诺言。我认为该API最终将进行改进,但尚未实现。
send()方法是否只是排队 所有数据要发送?如果套接字缓冲区已满,该怎么办? send()块会导致其他客户端饿死 封锁了一个?
WebSocket.send
最后调用了内置Net
模块的Socket.write
。 (有关该调用,请参见https://github.com/websockets/ws/blob/master/lib/sender.js底部的sendFrame
函数,有关Socket
类的文档,请参见https://nodejs.org/docs/latest-v8.x/api/net.html#net_class_net_socket。)
Socket.write
将在用户进程中缓冲数据。数据是按{Socket
分别缓冲的,因此通常这种缓冲不会影响在连接到其他客户端的其他Socket
上的传输。但是,Socket
可以缓冲的数据量没有限制。在极端情况下,一个Socket
的缓冲数据可能会消耗服务器进程的所有内存,并且由此导致的服务器崩溃将干扰向所有客户端的数据传递。
有几种方法可以避免此问题。想到的两种简单方法是:
为send
调用提供完成回调参数。该回调将传递给Socket.write
调用,当所有write
的数据都已写入内核时,该调用将触发该回调。如果您的服务器拒绝向该客户端发送更多数据,直到触发回调,则在该连接的用户空间中缓冲的数据量将被限制为接近最新send
的大小。 (它的大小不是完全一样,因为在传递给send
的原始数据之上,缓冲的数据将包括WebSocket框架,SSL框架和填充(如果您的连接已加密)。)或者
在准备为该连接上的bufferSize
数据之前,检查连接的Socket
的{{1}}属性。 send
指示该套接字当前在用户空间中缓冲的数据量。如果非零,请跳过该客户端的bufferSize
。