226

我正在使用 socket.io 和 node.js,直到现在它看起来还不错,但我不知道如何将消息从服​​务器发送到特定的客户端,如下所示:

client.send(message, receiverSessionId)

但无论是方法.send()还是.broadcast()方法似乎都不能满足我的需要。

我发现作为一种可能的解决方案是,该.broadcast()方法接受一个不向其发送消息的 SessionIds 数组作为第二个参数,因此我可以将一个包含当时连接的所有 SessionIds 的数组传递给服务器,除了那个我希望发送消息,但我觉得必须有更好的解决方案。

有任何想法吗?

4

12 回答 12

195

Ivo Wetzel 的回答在 Socket.io 0.9 中似乎不再有效。

简而言之,您现在必须保存socket.id并使用io.sockets.socket(savedSocketId).emit(...) 才能向其发送消息。

这就是我在集群的 Node.js 服务器中如何工作:

首先,您需要将 Redis 存储设置为存储,以便消息可以跨进程:

var express = require("express");
var redis = require("redis");
var sio = require("socket.io");

var client = redis.createClient()
var app = express.createServer();
var io = sio.listen(app);

io.set("store", new sio.RedisStore);


// In this example we have one master client socket 
// that receives messages from others.

io.sockets.on('connection', function(socket) {

  // Promote this socket as master
  socket.on("I'm the master", function() {

    // Save the socket id to Redis so that all processes can access it.
    client.set("mastersocket", socket.id, function(err) {
      if (err) throw err;
      console.log("Master socket is now" + socket.id);
    });
  });

  socket.on("message to master", function(msg) {

    // Fetch the socket id from Redis
    client.get("mastersocket", function(err, socketId) {
      if (err) throw err;
      io.sockets.socket(socketId).emit(msg);
    });
  });

});

我在这里省略了聚类代码,因为它使这更加混乱,但添加起来很简单。只需将所有内容添加到工作人员代码中即可。更多文档在这里http://nodejs.org/api/cluster.html

于 2012-03-22T08:21:36.247 回答
129

每个套接字连接一个带有名称的套接字 id 的房间,所以你可以

io.to('socket#id').emit('hey')

文档:http ://socket.io/docs/rooms-and-namespaces/#default-room

干杯

于 2014-12-03T11:28:38.337 回答
100

最简单,最优雅的方式

已验证使用 socket.io v3.1.1

这很简单:

client.emit("your message");

就是这样。好的,但它是如何工作的?

最小的工作示例

这是一个简单的客户端-服务器交互示例,其中每个客户端定期接收包含序列号的消息。每个客户端都有一个独特的序列,这就是“我需要向特定客户端发送消息”发挥作用的地方。

服务器

server.js

const
    {Server} = require("socket.io"),
    server = new Server(8000);

let
    sequenceNumberByClient = new Map();

// event fired every time a new client connects:
server.on("connection", (socket) => {
    console.info(`Client connected [id=${socket.id}]`);
    // initialize this client's sequence number
    sequenceNumberByClient.set(socket, 1);

    // when socket disconnects, remove it from the list:
    socket.on("disconnect", () => {
        sequenceNumberByClient.delete(socket);
        console.info(`Client gone [id=${socket.id}]`);
    });
});

// sends each client its current sequence number
setInterval(() => {
    for (const [client, sequenceNumber] of sequenceNumberByClient.entries()) {
        client.emit("seq-num", sequenceNumber);
        sequenceNumberByClient.set(client, sequenceNumber + 1);
    }
}, 1000);

服务器开始在端口 8000 上侦听传入连接。一旦建立了新连接,该客户端就会被添加到跟踪其序列号的映射中。服务器还侦听disconnect事件以在客户端离开时将其从地图中移除。

每一秒,都会触发一个计时器。当它这样做时,服务器会遍历映射并向每个客户端发送一条带有当前序列号的消息,然后立即递增它。仅此而已。十分简单。

客户

客户端部分甚至更简单。它只是连接到服务器并侦听seq-num消息,并在每次到达时将其打印到控制台。

client.js

const
    io = require("socket.io-client"),
    ioClient = io.connect("http://localhost:8000");

ioClient.on("seq-num", (msg) => console.info(msg));

运行示例

安装所需的库:

npm install socket.io@3.1.1 socket.io-client@3.1.1

运行服务器:

node server

通过运行以下命令打开其他终端窗口并生成任意数量的客户端:

node client

我还在这里准备了完整代码的要点。

于 2014-06-15T17:08:35.820 回答
97

好吧,您必须为此抓住客户(惊喜),您可以采用简单的方式:

var io = io.listen(server);
io.clients[sessionID].send()

这可能会破坏,我对此表示怀疑,但它总是有可能io.clients会改变,所以请谨慎使用上述内容

或者您自己跟踪客户端,因此您将它们添加到侦听器中您自己的clients对象并在connection侦听器中删除它们disconnect

我会使用后一种,因为根据您的应用程序,您可能希望在客户端上拥有更多状态,所以类似的东西clients[id] = {conn: clientConnect, data: {...}}可能会完成这项工作。

于 2011-01-10T14:14:13.423 回答
41

在 1.0 中,您应该使用:

io.sockets.connected[socketid].emit();
于 2014-10-30T01:56:34.820 回答
41

您可以使用

//只向发送者客户端发送消息

socket.emit('message', 'check this');

//或者你可以发送给包括发送者在内的所有监听者

io.emit('message', 'check this');

//发送给除发送者之外的所有监听者

socket.broadcast.emit('message', 'this is a message');

//或者你可以把它发送到一个房间

socket.broadcast.to('chatroom').emit('message', 'this is the message to all');

于 2016-06-25T07:25:06.380 回答
15

无论我们使用什么版本,如果我们只是 console.log() 我们在服务器端 nodejs 代码中使用的“io”对象,[例如 io.on('connection', function(socket) {...});] ,我们可以看到“io”只是一个json对象,并且有很多子对象存储了socket id和socket对象。

我正在使用 socket.io 版本 1.3.5,顺便说一句。

如果我们查看 io 对象,它包含,

 sockets:
  { name: '/',
    server: [Circular],
    sockets: [ [Object], [Object] ],
    connected:
     { B5AC9w0sYmOGWe4fAAAA: [Object],
       'hWzf97fmU-TIwwzWAAAB': [Object] },

在这里我们可以看到 socketids "B5AC9w0sYmOGWe4fAAAA" 等等。所以,我们可以这样做,

io.sockets.connected[socketid].emit();

同样,在进一步检查中,我们可以看到类似的部分,

 eio:
  { clients:
     { B5AC9w0sYmOGWe4fAAAA: [Object],
       'hWzf97fmU-TIwwzWAAAB': [Object] },

所以,我们可以通过这样做从这里检索一个套接字

io.eio.clients[socketid].emit();

此外,在我们拥有的引擎下,

engine:
 { clients:
    { B5AC9w0sYmOGWe4fAAAA: [Object],
      'hWzf97fmU-TIwwzWAAAB': [Object] },

所以,我们也可以写,

io.engine.clients[socketid].emit();

所以,我想我们可以通过上面列出的 3 种方式中的任何一种来实现我们的目标,

  1. io.sockets.connected[socketid].emit(); 或者
  2. io.eio.clients[socketid].emit(); 或者
  3. io.engine.clients[socketid].emit();
于 2015-06-17T10:30:10.683 回答
12

你可以这样做

在服务器上。

global.io=require("socket.io")(server);

io.on("connection",function(client){
    console.log("client is ",client.id);
    //This is handle by current connected client 
    client.emit('messages',{hello:'world'})
    //This is handle by every client
    io.sockets.emit("data",{data:"This is handle by every client"})
    app1.saveSession(client.id)

    client.on("disconnect",function(){
        app1.deleteSession(client.id)
        console.log("client disconnected",client.id);
    })

})

    //And this is handle by particular client 
    var socketId=req.query.id
    if(io.sockets.connected[socketId]!=null) {
        io.sockets.connected[socketId].emit('particular User', {data: "Event response by particular user "});
    }

在客户端,它很容易处理。

var socket=io.connect("http://localhost:8080/")
    socket.on("messages",function(data){
        console.log("message is ",data);
        //alert(data)
    })
    socket.on("data",function(data){
        console.log("data is ",data);
        //alert(data)
    })

    socket.on("particular User",function(data){
        console.log("data from server ",data);
        //alert(data)
    })
于 2015-07-27T16:17:50.100 回答
7

从 1.4.5 版开始,请确保在 io.to() 中提供正确前缀的 socketId。我正在使用客户端记录的 socketId 进行调试,它没有前缀,所以我最终永远搜索,直到我发现!因此,如果您拥有的 Id 没有前缀,您可能必须这样做:

io.to('/#' + socketId).emit('myevent', {foo: 'bar'});
于 2016-07-22T11:23:47.187 回答
6

io.sockets.sockets[socket.id].emit(...) 在 v0.9 中为我工作

于 2014-02-01T12:09:02.710 回答
4

您还可以保留客户的参考资料。但这会让你的记忆忙碌。

创建一个空对象并将您的客户设置到其中。

const myClientList = {};

  server.on("connection", (socket) => {
    console.info(`Client connected [id=${socket.id}]`);
     myClientList[socket.id] = socket;   
  });
  socket.on("disconnect", (socket) => {
    delete myClientList[socket.id];
  });

然后通过对象中的 id 调用您的特定客户端

myClientList[specificId].emit("blabla","somedata");
于 2020-04-16T07:26:09.807 回答
1

Socket.IO 允许您为套接字“命名空间”,这实际上意味着分配不同的端点或路径。

这可能会有所帮助: http ://socket.io/docs/rooms-and-namespaces/

于 2015-01-12T16:18:42.587 回答