用套接字向特定的客户端发送消息。io和node . js

时间:2022-11-17 07:37:27

I'm working with socket.io and node.js and until now it seems pretty good, but I don't know how to send a message from the server to an specific client, something like this:

我使用套接字。io和节点。js直到现在看起来还不错,但我不知道如何将消息从服务器发送到特定的客户机,类似这样:

client.send(message, receiverSessionId)

But neither the .send() nor the .broadcast() methods seem to supply my need.

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

What I have found as a possible solution, is that the .broadcast() method accepts as a second parameter an array of SessionIds to which not send the message, so I could pass an array with all the SessionIds connected at that moment to the server, except the one I wish send the message, but I feel there must be a better solution.

我发现作为一个可能的解决方案,是.broadcast()方法接受的sessionid作为第二个参数数组不发送消息,这样我就可以通过数组的sessionid向服务器连接的那一刻,除了一个我希望发送消息,但我觉得必须有一个更好的解决方案。

Any ideas?

什么好主意吗?

11 个解决方案

#1


81  

Well you have to grab the client for that (surprise), you can either go the simple way:

你必须抓住客户(惊喜),你可以走简单的路:

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

Which may break, I hardly doubt it, but it's always a possibility that io.clients might get changed, so use the above with caution

这可能会破裂,我几乎不怀疑,但它总是有可能。客户端可能会被更改,所以要谨慎使用上面的内容

Or you keep track of the clients yourself, therefore you add them to your own clients object in the connection listener and remove them in the disconnect listener.

或者您自己跟踪客户端,因此您将它们添加到连接侦听器中的自己的客户端对象,并在断开连接侦听器中删除它们。

I would use the latter one, since depending on your application you might want to have more state on the for the clients anyway, so something like clients[id] = {conn: clientConnect, data: {...}} might do the job.

我将使用后一种方法,因为根据您的应用程序,您可能希望在客户端上有更多的状态,因此类似client [id] = {conn: clientConnect, data:{…}{}可以做这个工作。

#2


156  

Ivo Wetzel's answer doesn't seem to be valid in Socket.io 0.9 anymore.

Ivo Wetzel的答案在Socket中似乎是无效的。io 0.9了。

In short you must now save the socket.id and use io.sockets.socket(savedSocketId).emit(...) to send messages to it.

简而言之,您现在必须保存套接字。id和使用io.sockets.socket(savedSocketId).emit(…)向它发送消息。

This is how I got this working in clustered Node.js server:

这就是我在群集节点中工作的方式。js服务器:

First you need to set Redis store as the store so that messages can go cross processes:

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

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

});

I omitted the clustering code here, because it makes this more cluttered, but it's trivial to add. Just add everything to the worker code. More docs here http://nodejs.org/api/cluster.html

我在这里省略了集群代码,因为它使这变得更加混乱,但是添加这些代码很简单。更多文档这里http://nodejs.org/api/cluster.html

#3


68  

each socket joins a room with a socket id for a name, so you can just

每个套接字将一个房间与一个套接字id连接起来作为一个名称,因此您可以

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

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

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

Cheers

干杯

#4


64  

The simplest, most elegant solution

It's as easy as:

这是一样容易:

client.emit("your message");

And that's it.

就是这样。

But how? Give me an example

What we all need is in fact a full example, and that's what follows. This is tested with the most recent socket.io version (2.0.3) and it's also using modern Javascript (which we should be all using by now).

我们需要的是一个完整的例子,这就是接下来要做的。这是用最近的套接字测试的。io版本(2.0.3),它还使用了现代Javascript(我们现在应该都在使用它)。

The example is comprised of two parts: a server and a client. Whenever a client connects, it starts receiving from the server a periodic sequence number. A new sequence is started for each new client, so the server has to keep track of them individually. That's where the "I need to send a message to a particular client" comes into play. The code is very simple to understand. Let's see it.

该示例由两个部分组成:服务器和客户机。每当客户端连接时,它就从服务器接收一个周期序列号。为每个新客户机启动一个新序列,因此服务器必须分别跟踪它们。这就是“我需要向特定客户发送消息”的作用所在。代码非常容易理解。让我们看看它。

Server

server.js

server.js

const
    io = require("socket.io"),
    server = io.listen(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);

The server starts listening on port 8000 for incoming connections. When one arrives, it adds that new client to a map so it can keep track of its sequence number. It also listens for that client's disconnect event, when it'll remove it from the map.

服务器开始监听端口8000上的传入连接。当其中一个到达时,它会将新客户端添加到映射中,这样它就可以跟踪它的序列号。它还监听客户端的断开连接事件,当它从映射中删除时。

Each and every second, a timer is fired. When it does, the server walks through the map and sends a message to every client with its current sequence number. It then increments it and stores the number back in the map. That's all that is to it. Easy peasy.

每一秒钟都有一个计时器被触发。当它这样做时,服务器遍历映射并向每个客户端发送一个带有当前序列号的消息。然后它会递增,并将数字存储在地图中。这就是它的全部。容易peasy。

Client

The client part is even simpler. It just connects to the server and listens for the seq-num message, printing it to the console every time it arrives.

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

client.js

client.js

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

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

Running the example

Install the required libraries:

安装所需的库:

npm install socket.io
npm install socket.io-client

Run the server:

运行服务器:

node server

Open other terminal windows and spawn as many clients as you want by running:

打开其他终端窗口,通过运行生成任意数量的客户端:

node client

I have also prepared a gist with the full code here.

我还准备了一个完整代码的要点。

#5


32  

In 1.0 you should use:

在1.0中,您应该使用:

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

#6


19  

You can use

您可以使用

//send message only to sender-client

//只向发送方发送消息

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

套接字。发出(“信息”、“检查这个”);

//or you can send to all listeners including the sender

//或者你可以发送给所有的听众,包括发送者。

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

io。发出(“信息”、“检查这个”);

//send to all listeners except the sender

//发送给除发件人之外的所有听众

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

socket.broadcast。发出('message', 'this is a message');

//or you can send it to a room

//或者你可以把它送到房间去

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

socket.broadcast.to(“聊天室”)。发送('message', 'this is the message to all');

#7


11  

Whatever version we are using if we just console.log() the "io" object that we use in our server side nodejs code, [e.g. io.on('connection', function(socket) {...});], we can see that "io" is just an json object and there are many child objects where the socket id and socket objects are stored.

无论使用什么版本,只要console.log()我们在服务器端nodejs代码中使用的“io”对象就可以了。io。在('connection', function(套接字){…};]上,我们可以看到“io”只是一个json对象,有许多子对象存储套接字id和套接字对象。

I am using socket.io version 1.3.5, btw.

我用插座。io 1.3.5版本,顺便说一句。

If we look in the io object, it contains,

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

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

here we can see the socketids "B5AC9w0sYmOGWe4fAAAA" etc. So, we can do,

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

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

Again, on further inspection we can see segments like,

再进一步观察,我们可以看到,

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

So, we can retrieve a socket from here by doing

因此,我们可以从这里检索套接字

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

Also, under engine we have,

同样,在我们的引擎下,

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

So, we can also write,

我们也可以这样写,

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

So, I guess we can achieve our goal in any of the 3 ways I listed above,

我想我们可以通过上面列出的三种方式来实现我们的目标,

  1. io.sockets.connected[socketid].emit(); OR
  2. io.sockets.connected[socketid].emit();或
  3. io.eio.clients[socketid].emit(); OR
  4. io.eio.clients[socketid].emit();或
  5. io.engine.clients[socketid].emit();
  6. io.engine.clients[socketid].emit();

#8


10  

You can do this

你可以这样做

On server.

在服务器上。

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

And on client, it is very easy to handle.

在客户端,很容易处理。

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

#9


5  

As of version 1.4.5, be sure you provide a properly prefixed socketId in io.to(). I was taking the socketId the Client logged to debug and it was without prefix so I ended up searching forever till I found out! So you might have to do it like this if the Id you have is not prefixed:

在1.4.5版本中,请确保在io.to()中提供了一个正确的前缀。我使用客户端登录的socketId进行调试,它没有前缀,所以我一直搜索,直到我发现!如果你的Id没有前缀,你可能需要这样做:

io.to('/#' + socketId).emit('myevent', {foo: 'bar'});

#10


4  

io.sockets.sockets[socket.id].emit(...) worked for me in v0.9

socket [socket.id].emit(…)在v0.9中对我有用

#11


0  

Socket.IO allows you to “namespace” your sockets, which essentially means assigning different endpoints or paths.

套接字。IO允许您给套接字命名空间,这实质上意味着分配不同的端点或路径。

This might help: http://socket.io/docs/rooms-and-namespaces/

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

#1


81  

Well you have to grab the client for that (surprise), you can either go the simple way:

你必须抓住客户(惊喜),你可以走简单的路:

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

Which may break, I hardly doubt it, but it's always a possibility that io.clients might get changed, so use the above with caution

这可能会破裂,我几乎不怀疑,但它总是有可能。客户端可能会被更改,所以要谨慎使用上面的内容

Or you keep track of the clients yourself, therefore you add them to your own clients object in the connection listener and remove them in the disconnect listener.

或者您自己跟踪客户端,因此您将它们添加到连接侦听器中的自己的客户端对象,并在断开连接侦听器中删除它们。

I would use the latter one, since depending on your application you might want to have more state on the for the clients anyway, so something like clients[id] = {conn: clientConnect, data: {...}} might do the job.

我将使用后一种方法,因为根据您的应用程序,您可能希望在客户端上有更多的状态,因此类似client [id] = {conn: clientConnect, data:{…}{}可以做这个工作。

#2


156  

Ivo Wetzel's answer doesn't seem to be valid in Socket.io 0.9 anymore.

Ivo Wetzel的答案在Socket中似乎是无效的。io 0.9了。

In short you must now save the socket.id and use io.sockets.socket(savedSocketId).emit(...) to send messages to it.

简而言之,您现在必须保存套接字。id和使用io.sockets.socket(savedSocketId).emit(…)向它发送消息。

This is how I got this working in clustered Node.js server:

这就是我在群集节点中工作的方式。js服务器:

First you need to set Redis store as the store so that messages can go cross processes:

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

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

});

I omitted the clustering code here, because it makes this more cluttered, but it's trivial to add. Just add everything to the worker code. More docs here http://nodejs.org/api/cluster.html

我在这里省略了集群代码,因为它使这变得更加混乱,但是添加这些代码很简单。更多文档这里http://nodejs.org/api/cluster.html

#3


68  

each socket joins a room with a socket id for a name, so you can just

每个套接字将一个房间与一个套接字id连接起来作为一个名称,因此您可以

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

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

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

Cheers

干杯

#4


64  

The simplest, most elegant solution

It's as easy as:

这是一样容易:

client.emit("your message");

And that's it.

就是这样。

But how? Give me an example

What we all need is in fact a full example, and that's what follows. This is tested with the most recent socket.io version (2.0.3) and it's also using modern Javascript (which we should be all using by now).

我们需要的是一个完整的例子,这就是接下来要做的。这是用最近的套接字测试的。io版本(2.0.3),它还使用了现代Javascript(我们现在应该都在使用它)。

The example is comprised of two parts: a server and a client. Whenever a client connects, it starts receiving from the server a periodic sequence number. A new sequence is started for each new client, so the server has to keep track of them individually. That's where the "I need to send a message to a particular client" comes into play. The code is very simple to understand. Let's see it.

该示例由两个部分组成:服务器和客户机。每当客户端连接时,它就从服务器接收一个周期序列号。为每个新客户机启动一个新序列,因此服务器必须分别跟踪它们。这就是“我需要向特定客户发送消息”的作用所在。代码非常容易理解。让我们看看它。

Server

server.js

server.js

const
    io = require("socket.io"),
    server = io.listen(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);

The server starts listening on port 8000 for incoming connections. When one arrives, it adds that new client to a map so it can keep track of its sequence number. It also listens for that client's disconnect event, when it'll remove it from the map.

服务器开始监听端口8000上的传入连接。当其中一个到达时,它会将新客户端添加到映射中,这样它就可以跟踪它的序列号。它还监听客户端的断开连接事件,当它从映射中删除时。

Each and every second, a timer is fired. When it does, the server walks through the map and sends a message to every client with its current sequence number. It then increments it and stores the number back in the map. That's all that is to it. Easy peasy.

每一秒钟都有一个计时器被触发。当它这样做时,服务器遍历映射并向每个客户端发送一个带有当前序列号的消息。然后它会递增,并将数字存储在地图中。这就是它的全部。容易peasy。

Client

The client part is even simpler. It just connects to the server and listens for the seq-num message, printing it to the console every time it arrives.

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

client.js

client.js

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

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

Running the example

Install the required libraries:

安装所需的库:

npm install socket.io
npm install socket.io-client

Run the server:

运行服务器:

node server

Open other terminal windows and spawn as many clients as you want by running:

打开其他终端窗口,通过运行生成任意数量的客户端:

node client

I have also prepared a gist with the full code here.

我还准备了一个完整代码的要点。

#5


32  

In 1.0 you should use:

在1.0中,您应该使用:

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

#6


19  

You can use

您可以使用

//send message only to sender-client

//只向发送方发送消息

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

套接字。发出(“信息”、“检查这个”);

//or you can send to all listeners including the sender

//或者你可以发送给所有的听众,包括发送者。

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

io。发出(“信息”、“检查这个”);

//send to all listeners except the sender

//发送给除发件人之外的所有听众

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

socket.broadcast。发出('message', 'this is a message');

//or you can send it to a room

//或者你可以把它送到房间去

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

socket.broadcast.to(“聊天室”)。发送('message', 'this is the message to all');

#7


11  

Whatever version we are using if we just console.log() the "io" object that we use in our server side nodejs code, [e.g. io.on('connection', function(socket) {...});], we can see that "io" is just an json object and there are many child objects where the socket id and socket objects are stored.

无论使用什么版本,只要console.log()我们在服务器端nodejs代码中使用的“io”对象就可以了。io。在('connection', function(套接字){…};]上,我们可以看到“io”只是一个json对象,有许多子对象存储套接字id和套接字对象。

I am using socket.io version 1.3.5, btw.

我用插座。io 1.3.5版本,顺便说一句。

If we look in the io object, it contains,

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

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

here we can see the socketids "B5AC9w0sYmOGWe4fAAAA" etc. So, we can do,

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

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

Again, on further inspection we can see segments like,

再进一步观察,我们可以看到,

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

So, we can retrieve a socket from here by doing

因此,我们可以从这里检索套接字

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

Also, under engine we have,

同样,在我们的引擎下,

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

So, we can also write,

我们也可以这样写,

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

So, I guess we can achieve our goal in any of the 3 ways I listed above,

我想我们可以通过上面列出的三种方式来实现我们的目标,

  1. io.sockets.connected[socketid].emit(); OR
  2. io.sockets.connected[socketid].emit();或
  3. io.eio.clients[socketid].emit(); OR
  4. io.eio.clients[socketid].emit();或
  5. io.engine.clients[socketid].emit();
  6. io.engine.clients[socketid].emit();

#8


10  

You can do this

你可以这样做

On server.

在服务器上。

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

And on client, it is very easy to handle.

在客户端,很容易处理。

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

#9


5  

As of version 1.4.5, be sure you provide a properly prefixed socketId in io.to(). I was taking the socketId the Client logged to debug and it was without prefix so I ended up searching forever till I found out! So you might have to do it like this if the Id you have is not prefixed:

在1.4.5版本中,请确保在io.to()中提供了一个正确的前缀。我使用客户端登录的socketId进行调试,它没有前缀,所以我一直搜索,直到我发现!如果你的Id没有前缀,你可能需要这样做:

io.to('/#' + socketId).emit('myevent', {foo: 'bar'});

#10


4  

io.sockets.sockets[socket.id].emit(...) worked for me in v0.9

socket [socket.id].emit(…)在v0.9中对我有用

#11


0  

Socket.IO allows you to “namespace” your sockets, which essentially means assigning different endpoints or paths.

套接字。IO允许您给套接字命名空间,这实质上意味着分配不同的端点或路径。

This might help: http://socket.io/docs/rooms-and-namespaces/

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