Socket.IO-如何获取已连接套接字/客户端的列表?


159

我正在尝试获取当前已连接的所有套接字/客户端的列表。

io.sockets 不幸的是,它不返回数组。

我知道我可以使用数组保留自己的列表,但是由于以下两个原因,这并不是最佳解决方案:

  1. 冗余。Socket.IO已保留此列表的副本。

  2. Socket.IO提供了为客户端设置任意字段值的方法(即:),socket.set('nickname', 'superman')因此如果我要维护自己的列表,则需要跟上这些更改。

救命?


您不能仅将io.sockets转换为数组吗?

2
在0.7.6 io.sockets.sockets中是一个简单的哈希对象id => socket
mak

1
我注意到了,但是它的行为很奇怪(看起来不像标准的套接字对象)。例如,我尝试过:pastebin.com/fxuzVckS,但这是说套接字对象不包含“ get”方法。
安迪·辛

3
socket是id,io.sockets.sockets[socket]是套接字。

2
第一个参数是err,如果使用内存存储,则始终为null.get('nickname', function(err, nickname) { ... })

Answers:


173

在Socket.IO 0.7中,您clients在名称空间上有一个方法,该方法返回所有已连接套接字的数组。

没有名称空间的API:

var clients = io.sockets.clients();
var clients = io.sockets.clients('room'); // all users from room `room`

对于命名空间

var clients = io.of('/chat').clients();
var clients = io.of('/chat').clients('room'); // all users from room `room`

希望这对以后的人有帮助

注意:此解决方案适用于1.0之前的版本


2020年3月6日更新

从1.x及更高版本开始,请参考以下链接:在socket.io中获取聊天室中的人数


3
我认为他们已经放弃了的客户方法1.0 ...只是检查出的那一刻...
marksyzm

7
他们完全放弃了1.0中的所有内容。但是1.0已经发布多年了。在1.0中,您必须使用connected名称空间的对象。
3rdEden

6
@ 3rdEden,使用名称空间的连接对象的语法是什么?var clients = io.sockets.connected();显然不起作用。谢谢
卡亚吐司2014年


TypeError:fn.bind不是函数
Iman Marashi

101

Socket.io 1.4

Object.keys(io.sockets.sockets); 给您所有连接的插座。

Socket.io 1.0 从socket.io 1.0开始,实际接受的答案不再有效。因此,我做了一个小功能,可以用作临时修复程序:

function findClientsSocket(roomId, namespace) {
    var res = []
    // the default namespace is "/"
    , ns = io.of(namespace ||"/");

    if (ns) {
        for (var id in ns.connected) {
            if(roomId) {
                var index = ns.connected[id].rooms.indexOf(roomId);
                if(index !== -1) {
                    res.push(ns.connected[id]);
                }
            } else {
                res.push(ns.connected[id]);
            }
        }
    }
    return res;
}

Api for No名称空间变为

// var clients = io.sockets.clients();
// becomes : 
var clients = findClientsSocket();

// var clients = io.sockets.clients('room');
// all users from room `room`
// becomes
var clients = findClientsSocket('room');

命名空间的 Api 变为:

// var clients = io.of('/chat').clients();
// becomes
var clients = findClientsSocket(null, '/chat');

// var clients = io.of('/chat').clients('room');
// all users from room `room`
// becomes
var clients = findClientsSocket('room', '/chat');

另请参阅此相关问题,在该问题中,我提供了一个函数,该函数返回给定房间的套接字。

function findClientsSocketByRoomId(roomId) {
var res = []
, room = io.sockets.adapter.rooms[roomId];
if (room) {
    for (var id in room) {
    res.push(io.sockets.adapter.nsp.connected[id]);
    }
}
return res;
}

Socket.io 0.7

没有命名空间的 API :

var clients = io.sockets.clients();
var clients = io.sockets.clients('room'); // all users from room `room`

对于命名空间

var clients = io.of('/chat').clients();
var clients = io.of('/chat').clients('room'); // all users from room `room`

注意:由于socket.io API似乎容易崩溃,并且某些解决方案依赖于实现细节,因此可能需要自己跟踪客户端:

var clients = [];

io.sockets.on('connect', function(client) {
    clients.push(client); 

    client.on('disconnect', function() {
        clients.splice(clients.indexOf(client), 1);
    });
});

3
这次真是万分感谢。我很惊讶他们淘汰了此功能。
泰勒·斯科特

1
@TylerScott我也是,尤其是考虑到他们的迁移指南中没有涉及这一点(除非我遗漏了一些东西)。 socket.io/docs/migrating-from-0-9
nha 2014年

@nha,这对我不起作用,但返回一个整数数组,例如0、1和2等,而不是套接字数组。有任何想法吗?
ThePixelPony 2014年

多个节点呢?因为我在Redis存储中使用了多个节点
John Nguyen

3
@nha您的答案是正确的,但不适用于带有Redis存储服务器的多个节点。从1节点进程开始,您无法使用ns.connected [id]检查套接字是否已连接-John
Nguyen

46

在socket.io 1.0之后,我们不能使用

io.sockets.clients(); 
or
io.sockets.clients('room'); 

不再。相反,您可以使用以下内容

var clients_in_the_room = io.sockets.adapter.rooms[roomId]; 
for (var clientId in clients_in_the_room ) {
  console.log('client: %s', clientId); //Seeing is believing 
  var client_socket = io.sockets.connected[clientId];//Do whatever you want with this
}

3
我改变var clients_in_the_room = io.sockets.adapter.rooms[roomId].sockets
法比奥Zangirolami

37

使用Socket.IO 1.x:

获取连接的客户端的数组:

io.engine === io.eio // => true
Object.keys(io.engine.clients) // => [ 'US8AxrUrrDF_G7ZUAAAA', 'Ov2Ca24Olkhf2NHbAAAB' ]
Object.keys(io.eio.clients)    // => [ 'US8AxrUrrDF_G7ZUAAAA', 'Ov2Ca24Olkhf2NHbAAAB' ]

获取连接的客户端数:

io.engine.clientsCount // => 2
io.eio.clientsCount    // => 2

32

在socket.io 1.3中非常简单:

io.sockets.sockets-是一个包含连接的套接字对象的数组。如果将用户名存储在每个套接字中,则可以执行以下操作:

io.sockets.sockets.map(function(e) {
    return e.username;
})

繁荣。您具有所有已连接用户的名称。


2
谢谢!为简单起见,+ 1。您是否知道此方法与Joseph Dykstra的答案之间是否有区别?(Object.keys(io.engine.clients)
–cyclingLinguist

4
在v1.4.5上不起作用。仍在研究解决方案
Nuno Furtado 2016年

您找到它了吗?\
ocram

2
类型错误:io.sockets.sockets.map不是一个函数
基拉伊伊什特万

23

我今天经历了这种痛苦。如果他们可以为其API编写适当的文档,Socket.io将会更好。

无论如何,我尝试研究io.sockets并发现了许多可以使用的选项:

io.sockets.connected //Return {socket_1_id: {}, socket_2_id: {}} . This is the most convenient one, since you can just refer to io.sockets.connected[id] then do common things like emit()
io.sockets.sockets //Returns [{socket_1}, {socket_2}, ....]. Can refer to socket_i.id to distinguish
io.sockets.adapter.sids //Return {socket_1_id: {}, socket_2_id: {}} . Looks similar to the first one but the object is not actually the socket, just the information.

// Not directly helps but still relevant
io.sockets.adapter.rooms //Returns {room_1_id: {}, room_2_id: {}}
io.sockets.server.eio.clients //Return client sockets
io.sockets.server.eio.clientsCount //Return number of connected clients

另外,请注意,将socket.io与名称空间一起使用时,由于io.sockets成为数组而不是对象,因此上述方法将中断。要解决,只需将io.sockets替换为io(即io.sockets.connected变为io.connected,io.sockets.adapter.rooms变为io.adapter.rooms ...)

在socket.io 1.3.5上测试


1
@Зелёный如果您不使用名称空间,它将起作用。如果您使用的是命名空间,请更改为io.server.eio.clientsCount
Thanh Nguyen

2
是的,官方文档可能会有很大改进
CodeAndCats

18

版本+2.0

在版本+2.0中,您指定要查询的名称空间/房间/节点。

与广播一样,默认是来自默认名称空间('/')的所有客户端:

const io = require('socket.io')();  
io.clients((error, clients) => {
      if (error) throw error;
      console.log(clients); // => [6em3d4TJP8Et9EMNAAAA, G5p55dHhGgUnLUctAAAB]
});

获取连接到特定名称空间的客户端ID列表(如果适用,跨所有节点)。

const io = require('socket.io')();
io.of('/chat').clients((error, clients) => {
     if (error) throw error;
     console.log(clients); // => [PZDoMHjiu8PYfRiKAAAF, Anw2LatarvGVVXEIAAAD]
});

使所有客户端进入名称空间的示例:

const io = require('socket.io')();
io.of('/chat').in('general').clients((error, clients) => {
      if (error) throw error;
      console.log(clients); // => [Anw2LatarvGVVXEIAAAD] 
});

这来自官方文档:Socket.IO Server-API


1
有没有办法查看所有套接字对象?例如,如果我socket.username在连接时向每个套接字添加属性,有没有办法查看所有这些套接字对象(包括我添加到每个套接字的自定义属性)?(作为参考,我当前正在使用全局对象变量来在客户端连接时存储其他套接字信息-因此不询问如何设置-只是想知道是否有一种方法可以通过“默认”查看所有套接字对象) 。
user1063287

1
嗯,每个这样的回答,我想你可以看到所有的连接插座console.log(io.sockets.connected)-这似乎是一个对象,其中每个属性值是“插座对象”,其中包含这些属性nspserveradaptorid(串)clientconnroomsacksconnecteddisconnectedhandshakefnsflags_rooms_events_eventsCount最后username是自定义属性我添加到每个插座的连接。
user1063287

17

我认为我们可以从服务器访问套接字对象,并且可以分配昵称并指出其套接字ID,

io.sockets.on('connection',function(socket){ 
    io.sockets.sockets['nickname'] = socket.id;
    client.on("chat", function(data) {      
        var sock_id = io.sockets.sockets['nickname']
        io.sockets.sockets[sock_id].emit("private", "message");
    });    
});

在上,disconnect请从中删除昵称io.sockets.sockets


“ client.on”的目的是什么?您可以像这样使用您的代码(仅接受来自1个套接字的数据)吗?

9

这是在socket.io 1.3中访问它的最佳方法

Object.keys(socket.adapter.rooms[room_id])


请让我分享这个例子, var room = io.sockets.adapter.rooms[room_id]; var connections = _.map(Object.keys(room), function(socketId){ return (io.sockets.connected[socketId].connected == true) });
Hany Alsamman

5

对于只需要COUNT个连接的客户端的人,我相信这可以做到:

io.sockets.manager.server.connections


不是连接的客户数,没有经过测试。(更多)
mrzmyr 2012年

5
为了获得准确的计数使用io.sockets.clients().length
Ivo

2
目前,这两个io.sockets.manager.server.connectionsio.sockets.clients().length不工作。这对我有用-仅用于计数- io.engine.clientsCount和用于客户列表- io.engine.clientsCount。由于它已经这样保持了3年以上。似乎是获取连接信息的可靠方法。(基于约瑟夫·迪克斯特拉的回答)
阿斯温·拉玛克里希南

5

Socket.io 1.4.4

为您提供示例代码。

function get_clients_by_room(roomId, namespace) {
        io.of(namespace || "/").in(roomId).clients(function (error, clients) {
            if (error) { throw error; }
            console.log(clients[0]); // => [Anw2LatarvGVVXEIAAAD]
            console.log(io.sockets.sockets[clients[0]]); //socket detail
            return clients;
        });
    }

我认为可以帮助某人此代码块。


4

在Socket.IO 1.4中

获取所有已连接用户的数组:

var allConnectedClients = Object.keys(io.sockets.connected);// This will return the array of SockeId of all the connected clients

要获得所有客户的数量:

var clientsCount = io.engine.clientsCount ; // This will return the count of connected clients

我确认此作品在版本1.5.1 socket.io
塞巴斯蒂安

3

从socket.io 1.5开始,请注意对indexOf的更改似乎已过时,并已替换为valueOf

function findClientsSocket(roomId, namespace) {
    var res = [];
    var ns = io.of(namespace ||"/");    // the default namespace is "/"

    if (ns) {
        for (var id in ns.connected) {
            if (roomId) {
                //var index = ns.connected[id].rooms.indexOf(roomId) ;
                var index = ns.connected[id].rooms.valueOf(roomId) ; //Problem was here

                if(index !== -1) {
                    res.push(ns.connected[id]);
                }
            } else {
                res.push(ns.connected[id]);
            }
        }
    }
    return res.length;
}

对于socket.io 2.0.3版,以下代码适用:

function findClientsSocket(io, roomId, namespace) {
    var res = [],
        ns = io.of(namespace ||"/");    // the default namespace is "/"

    if (ns) {
        for (var id in ns.connected) {
            if(roomId) {
                // ns.connected[id].rooms is an object!
                var rooms = Object.values(ns.connected[id].rooms);  
                var index = rooms.indexOf(roomId);
                if(index !== -1) {
                    res.push(ns.connected[id]);
                }
            }
            else {
                res.push(ns.connected[id]);
            }
        }
    }
    return res;
}

你无法想象你救了我多少痛苦
nicholaswmin

但是socket.io版本还不是1.5!现在是1.4.8
leszek.hanusz

@MoleIsKing Obrigado好友!

2

在socket.io 1.3上,我已经完成了2行

var usersSocketIds = Object.keys(chat.adapter.rooms['room name']);
var usersAttending = _.map(usersSocketIds, function(socketClientId){ return chat.connected[socketClientId] })

2

Socket.io 1.7.3(+):

函数getConnectedList()
{
    让清单= []
    
    为(让io.sockets.connected中的客户端)
    {
        list.push(客户)
    }
    
    返回清单
}

console.log(getConnectedList())

//返回['yIfhb2tw7mxgrnF6AAAA','qABFaNDSYknCysbgAAAB']


2

对于2.3版本,它可以正常工作,并且也会为您提供套接字,在我看来,使用一段时间后,socketIo的更改速度太快,并且文档几乎没有可读性。

ioSite.of('/').in(roomId).clients((error, clients) => {
    if (error) throw error;
    for (var i=0;i<clients.length;i++) {
        clientId=clients[i];
        console.log(clientId);

        // load the socket of your namespace
        var socket=ioSite.of('/').in(roomId).connected[clientId]
        console.log(socket.constructor.name);
        console.log(socket.id);
    }
});

仍然感觉不对,因为我总是对套接字有这种感觉


1
我开始认为这是一个垃圾库。唯一一件正确的事就是无缝地传输多种类型的数据(json,二进制文件等),否则整个体系结构将变得毫无用处,并且无法在1个聊天应用程序中扩展到超过1个
Muhammad Umer

1

我相信您可以从套接字的manager属性中访问它吗?

var handshaken = io.manager.handshaken;
var connected = io.manager.connected;
var open = io.manager.open;
var closed = io.manager.closed;

3rdEden的答案对我不起作用,因为阵列返回断开连接的客户端存在问题,这不计入数。结果证明Object.keys(io.manager.open).length是最可靠的计数。io.of('/ namespace')。manager.open(如果使用名称空间)。
Wes Johnson

1

我在这里看到了很多很好的答案,在很多有用的地方,但并不是我所需要的。我正在为pubsub功能使用套接字,感兴趣的客户端可以在其中监听给定记录中的任何更改。

我的具体问题是同一插座多次连接到同一房间。解决方案是检查套接字是否已在其房间属性中拥有该房间。

var room = myObj.id.toString();
if (socket.rooms.indexOf(room) === -1) {
    socket.join(room);
    socket.emit('subscribed', {to : room});
} else {
    console.log("Already in room");
}

希望这对某人有帮助。


我认为,如果通过套接字连接使客户端加入会议室,则可以避免使用“ if”语句。
Chayemor 2015年

myObj来自哪里?您是如何得出这一价值的?
Michael Draper 2015年

@MikeDraper myObject是充当通道的数据库中的记录。这解决了这种情况,您希望每当数据库发生更改时都更新所有客户端,例如,用户更新其名称,并且所有连接的客户端都获得更新。因此,鉴于实例ID是唯一的(BSON),我为它创建了一个房间。对于我的用例来说,这是一个非常具体的值,所以如果造成任何混乱,我们深表歉意。让我知道您是否需要帮助:)
Gus Ortiz 2015年

@JMR由于我的应用程序的性质,碰巧一个套接字被订阅了多个,这就是为什么我必须添加该检查的原因。
Gus Ortiz'2

1

如果不使用名称空间或房间,这是Socket.IO 1.0+中最简单的方法。

io.nsps["/"].sockets.length

这将检查默认的名称空间并确定套接字数组的长度,而无需使用 Object.keys()


1

从1.5.1版开始,我可以使用以下命令访问名称空间中的所有套接字:

var socket_ids = Object.keys(io.of('/namespace').sockets);
socket_ids.forEach(function(socket_id) {
    var socket = io.of('/namespace').sockets[socket_id];
    if (socket.connected) {
        // Do something...
    }
});

由于某种原因,他们使用普通对象而不是数组来存储套接字ID。


这个作品。io.of('')中的空字符串无需命名空间即可工作。
基拉伊伊什特万

@KirályIstván我已经有一段时间没有对此进行研究了,但是我认为of()在这种情况下,您可以完全删除链接的呼叫。
rppc

1

对于集群模式,使用redis-adaptor

io.in(<room>).clients(function(err, clients) {

});

由于每个插槽本身就是一个房间,因此可以使用该插槽查找是否存在插槽。


0

这是使用ES6生成器将连接的套接字的哈希从名称空间转换为数组的快速方法(适用于socket.io> = v1.0.0):

io.on('connection', function(socket) {
  var hash = io.of('/').connected
  var list = null

  hash[Symbol.iterator] = function*() {
    // for..of loop to invoke Object.keys() default iterator
    // to get the array values instead of the keys
    for(var id of Object.keys(hash)) yield hash[id]
  }

  list = [...hash]
  console.log(Array.isArray(list)) // true
})

0

我不知道这是否还会继续。但是我最终使用的是这样的东西(我在每个连接的套接字上保留一个会话对象,而该对象又包含用户名和其他信息:

var connectedUsers = Object.keys(io.sockets.connected).map(function(socketId) {
    return io.sockets.connected[socketId].session.username;
});

0

如果项目具有socket.io群集,则意味着正在使用socket.io-redis适配器。

如果是上述情况,则必须通过socket.io-redis适配器执行获取所有已连接套接字id的过程。下面的示例可用于此目的;

io.of('/').adapter.clients(function (err, clients) {
  console.log("clients: ", clients); // an array containing all connected socket ids
});


io.of('/').adapter.allRooms(function (err, rooms) {
  console.log("all rooms: ", rooms);
});

请访问socket.io-redis github页面以获取更多详细信息。


0

socket.io@1.7.3

我使用Object.Keys来获取连接的套接字数组。然后在同一数组中使用map函数进行迭代以构建新的对象数组

var connectedUsers = Object.keys(io.sockets.connected).map(function(socketId) {
    return { socket_id : socketId, socket_username: io.sockets.connected[socketId].username };
});

// test
console.log(connectedUsers);

也许这个答案可以帮助获得套接字ID /用户名数组。


1
嗨-您能用英语解释如何解决此问题吗?这样,它不仅是纯代码的答案。谢谢!
Max von Hippel

0

v.10

var clients = io.nsps['/'].adapter.rooms['vse'];
/* 
'clients' will return something like:
Room {
sockets: { '3kiMNO8xwKMOtj3zAAAC': true, FUgvilj2VoJWB196AAAD: true },
length: 2 }
*/
var count = clients.length;  // 2
var sockets = clients.map((item)=>{  // all sockets room 'vse'
       return io.sockets.sockets[item];
      });
sample >>>
var handshake  = sockets[i].handshake; 
handshake.address  .time .issued ... etc.

1
如果您可以添加一些上下文说明“为什么这是最好的方法”以及您的答案如何为上述所有答案中的任何内容添加内容,那将是很好的。代码是东西,但是答案也应该有一些解释。如您所见,这个问题还有许多其他答案。您的答案必须给主题带来更多的东西,否则,这是多余的。
内森·里珀特

有了socket.io 2.1.1 ,我得到的TypeError: clients.map is not a function尽管它看起来很有希望,但我不完全确定上面的示例将实现什么-我希望它可以自动创建一个包含用户名的客户端对象数组:)。
user1063287
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.