Node.js 在具有多进程的NodeJ中存储套接字

Node.js 在具有多进程的NodeJ中存储套接字,node.js,sockets,Node.js,Sockets,我有一个NodeJS TCP服务器,它将每个套接字连接存储在一个阵列中,其中包含一些我需要与之关联的杂项信息: var clients = []; net.createServer(sslOptions, function (_socket) { _socket.name = 'someName'; _sockect.foo = 'bar'; clients.push(_socket); } 对于某些业务逻辑内容,服务器经常迭代阵列客户机。有时会触发条件,我需要断开其

我有一个NodeJS TCP服务器,它将每个套接字连接存储在一个阵列中,其中包含一些我需要与之关联的杂项信息:

var clients = [];

net.createServer(sslOptions, function (_socket) {
    _socket.name = 'someName';
    _sockect.foo = 'bar';
    clients.push(_socket);
}
对于某些业务逻辑内容,服务器经常迭代阵列客户机。有时会触发条件,我需要断开其中一个插座:

if(condition) {
  for(let x = 0; x < clients.length; x++) {
    if(clients[x].name == 'someName') {
      clients[x].disconnect();
      clients.splice(x, 1);
      return;
    }
  }
}
if(条件){
for(设x=0;x
有两件事让我担心这种方法。如果我决定使用Nodejs Process Manager或其他任何Nodejs Process Manager复制我的应用程序以实现负载平衡,那么不同的进程如何共享相同的阵列客户端?如果一个进程正在迭代数组,而另一个进程正在删除索引,那么可能会出现争用情况,最终导致错误的断开连接和删除

当然,一个解决方案是使用原子数据库之类的东西,但我不知道如何在Mongo或Redis之类的东西中存储套接字

不同的进程如何共享相同的阵列客户端

他们没有

两个node.js进程不能访问同一个数组(它们位于不同的进程和不同的Javascript解释器中),因此没有机会直接共享数据,也没有相应的竞争条件

如果一个进程正在迭代数组,而另一个进程正在删除索引,那么可能会出现争用情况,最终导致错误的断开连接和删除

因为Javascript只在一个线程中运行所有Javascript,所以不能让多个Javascript同时尝试修改同一数组。如果要迭代数组并进行异步调用,则需要执行一些安全操作,因为数组在等待异步响应时可能会更改,但在同步
for
循环运行时它不会更改

要了解如何使您的工作类似于使用多个node.js进程,您可以从socket.io服务器如何支持集群学到很多东西,因为它有相同的基本问题需要解决。他们希望能够发送到所有连接的套接字(跨所有集群服务器)或任何特定连接(无论消息来自哪个服务器以及连接的客户端实际连接到哪个服务器)

对于socket.io,它们基本上使用所有集群进程都可以访问的公共中间存储(在它们的例子中是redis数据存储)。由于redis是为多用户访问而设计的,因此客户端可以谨慎使用其API并避免竞争条件。然后,redis存储区用于存储每个已连接用户的元数据以及服务器进程包含其当前连接的指示器

要从任何集群服务器进程向特定用户发送消息,请从redis存储中获取该用户的数据。如果用户在连接到本地服务器进程(您正在从中执行查找的进程)上,那么您可以直接从元数据获取他们的ID,并在您自己的本地连接客户端列表中查找他们,然后发送到他们的套接字

如果它们连接到不同的服务器,则向该服务器发送一条消息,要求它们将消息中继到特定的套接字ID值。当服务器接收到消息时,它会在自己的连接到其进程的客户端列表中查找该ID,获取它们的套接字并向它们发送消息

当客户端连接或断开与任何群集进程的连接时,会从redis存储中添加或删除连接。请记住,您不会(也不能)在redis存储中存储实际的套接字对象,因为套接字对象是特定进程的本地对象。您只在redis store和服务器ID中存储元数据,因此任何查询redis store的人都可以确定连接了哪些用户以及他们当前连接的服务器。您通常会使用一个唯一的用户名或其他唯一的ID来表示每个用户,类似地,服务器将由某种允许您连接到它们的ID(可能是主机/端口号)来表示

为了避免redis store中的竞争条件,您只需要在修改数据时使用良好的多用户数据管理实践和正确的redis API,大多数问题都可以避免。关于比赛条件的进一步建议需要更多关于你试图修改什么的细节。但是,大多数情况下,您只是在连接时添加一个已连接的用户,在断开连接时删除一个已连接的用户,当使用正确的API时,这两种操作都是原子操作。如果您获取一个用户列表,然后对其进行操作,那么如果在您查询这些用户的时间和您尝试实际发送给他们的时间之间,这些用户断开连接,那么您将有一个潜在的竞争条件。为此,您只需做好准备,在尝试向错误发送消息时,如果错误碰巧消失,就可以适当地处理错误

每个单独的node.js进程都将维护自己连接到自己进程的套接字数组。由于node.js以单线程的形式运行js,并且该数组不与任何其他进程或线程共享,因此,如果代码编写正确,仅访问或维护该数组就不会出现竞争条件

当然,一个解决方案是使用原子数据库之类的东西,但我不知道如何在Mongo或Redis之类的东西中存储套接字

这些数据库中没有存储套接字。存储套接字ID值和服务器ID值。服务器ID值(可以是主机/端口字符串)可用于连接到具有该套接字ID连接的正确服务器。然后,接收服务器可使用该套接字ID在其自己的阵列中查找其自身连接的实际套接字对象。

我想您必须合作
io.of('/').adapter.clients((err, clients) => {
   console.log(clients); // an array containing all connected socket ids
});

io.of('/').adapter.clients(['room1', 'room2'], (err, clients) => {
   console.log(clients);
});

// you can also use

io.in('room3').clients((err, clients) => {
   console.log(clients); // an array containing socket ids in 'room3'
});