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

时间:2011-07-03 15:58:06

标签: node.js socket.io

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

不幸的是,

io.sockets没有返回数组。

我知道我可以使用数组保留自己的列表,但不要认为这是一个最佳解决方案有两个原因:

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

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

  3. 帮助?

31 个答案:

答案 0 :(得分:160)

在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之前的版本

答案 1 :(得分:93)

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变为

// 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');

另请参阅此related question,其中我提供了一个返回给定房间的套接字的函数。

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);
    });
});

答案 2 :(得分: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 :(得分:33)

使用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

答案 4 :(得分:31)

在socket.io 1.3中非常简单:

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

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

动臂。您拥有所有已连接用户的名称。

答案 5 :(得分:21)

我今天经历了这种痛苦。如果他们可以为他们的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替换io.sockets(即io.sockets.connected变为io.connected,io.sockets.adapter.rooms变为io.adapter.rooms ......)

在socket.io 1.3.5上测试

答案 6 :(得分: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删除昵称。

答案 7 :(得分:11)

版本+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

答案 8 :(得分:9)

这是在socket.io 1.3

中访问它的最佳方法

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

答案 9 :(得分:5)

对于那些只想要COUNT个连接客户端的人,我相信会这样做:

io.sockets.manager.server.connections

答案 10 :(得分: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;
        });
    }

我认为这将有助于此代码阻止。

答案 11 :(得分: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

答案 12 :(得分:3)

从socket.io 1.5开始,请注意indexOf的变化,该变化似乎是de depreciated,并被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;
}

答案 13 :(得分:2)

2021 更新 V4.0+

没有一个答案对我有用。我会让你免于痛苦。从 1.0 开始,他们的 API 和文档发生了很大变化。

Server Api 所有可用选项

但你需要深入挖掘here

// return all Socket instances
var clients = io.sockets;

clients.sockets.forEach(function(data,counter){

//console.log(data);//maps

var socketid =  data.id;//log ids
var isConnected = data.connected//true,false;

});

答案 14 :(得分: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] })

答案 15 :(得分:2)

namespace.allSockets()

返回承诺

io.allSockets() 主命名空间中所有连接的套接字 id

io.in('room').allSockets() // 'room' 中所有连接的 id

io.of('/namespace').allSockets() // '/namespace' 中所有连接的 ids(你也可以将它与房间结合起来)

答案 16 :(得分:2)

socket.io@3.0

 io.in('room1').sockets.sockets.forEach((socket,key)=>{
        console.log(socket);
    })

room1 中的所有 socket 实例

答案 17 :(得分:2)

Socket.io 1.7.3(+):

function getConnectedList ()
{
    let list = []

    for ( let client in io.sockets.connected )
    {
        list.push(client)
    }

    return list
}

console.log( getConnectedList() )

// returns [ 'yIfhb2tw7mxgrnF6AAAA', 'qABFaNDSYknCysbgAAAB' ]

答案 18 :(得分:1)

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

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

});

由于每个套接字本身都是一个房间,因此可以找到使用相同的套接字。

答案 19 :(得分:1)

对于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);
    }
});

这仍然感觉不对,因为我一直有这种感觉与插座Io莫名其妙

答案 20 :(得分:1)

我相信你可以从socket的manager属性访问它吗?

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

答案 21 :(得分: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。

答案 22 :(得分:1)

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

^                   # Start
(?=.*[A-Z])         # lookahead to assert a capital letter
(?=.*[aAeEiIoOuU])  # lookahead to assert a vowel
(?=.*\d)            # lookahead to assert a digit
(?:                 # non-capturing group start
   ([a-zA-Z\d])     # match any letter or digit and capture it in group #1
   (?!\1)           # negative lookahead to ensure same char is not repeated
)+                  # non-capturing group end, + ensures 1 ore more of it
$                   # end

这将查看默认命名空间并确定套接字数组的长度,而无需使用io.nsps["/"].sockets.length

答案 23 :(得分:1)

我在这里看到很多好的答案,很多很有用的地方,但不是我需要的。我正在使用socket作为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");
}

希望这有助于某人。

答案 24 :(得分: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 page了解详情。

答案 25 :(得分:0)

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

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

答案 26 :(得分: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 /用户名数组。

答案 27 :(得分: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.

答案 28 :(得分:0)

以下是使用ES6生成器将连接套接字的哈希值从命名空间转换为数组的快速方法(适用于socket.io&gt; = 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
})

答案 29 :(得分:0)

io.sockets.sockets.keys()

这对我有帮助。

答案 30 :(得分:0)

socket.io 4.0.0 版

在服务器端列出我使用的所有活动套接字的一些属性:

function listSocketsProperty(myProperty){
  let sck = io.sockets.sockets
  const mapIter = sck.entries()
  while(1){
    let en = mapIter.next().value?.[0]
    if(en) console.log( sck.get(en)[myProperty] )
    else break
  }
}

说明:

sck=io.sockets.sockets 是一个 Map 对象。

entries() 方法返回一个新的 Iterator 对象,该对象包含 Map 对象中每个元素的 [key, value] 对。

en=mapIter.next().value?.[0]获取 key - pair 的第一个元素。

如果没有更多的迭代,en 变为 undefined,这会中断 while 循环。

示例:

我的套接字有属性“playerName”,我想列出所有房间中所有活跃玩家的名字。为此,我只需调用函数:

listSocketsProperty('playerName')

然后进入控制台,如下所示:

John
Peter
Zoran
etc.