Javascript 使用 socket.io 和 node.js 向特定客户端发送消息

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4647348/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 13:26:15  来源:igfitidea点击:

Send message to specific client with socket.io and node.js

javascriptnode.jswebsocketsocket.ioserver-side

提问by Rodolfo Palma

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:

我正在使用 socket.io 和 node.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()方法接受一个不向其发送消息的 SessionIds 数组作为第二个参数,因此我可以将一个包含当时连接的所有 SessionIds 的数组传递给服务器,除了一个我希望发送消息,但我觉得必须有更好的解决方案。

Any ideas?

有任何想法吗?

采纳答案by Ivo Wetzel

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 doubt it, but it's always a possibility that io.clientsmight get changed, so use the above with caution

这可能会中断,我对此表示怀疑,但总是有可能io.clients会发生变化,因此请谨慎使用上述内容

Or you keep track of the clients yourself, therefore you add them to your own clientsobject in the connectionlistener and remove them in the disconnectlistener.

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

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

我会使用后一个,因为根据您的应用程序,无论如何您可能希望在客户端上拥有更多状态,因此clients[id] = {conn: clientConnect, data: {...}}可能会完成这项工作。

回答by Epeli

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.idand use io.sockets.socket(savedSocketId).emit(...)to send messages to it.

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

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

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

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

首先,您需要将 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);
    });
  });

});

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

回答by Matic Kogov?ek

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

干杯

回答by Lucio Paiva

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

事实上,我们都需要一个完整的例子,这就是下面的内容。这是用最新的 socket.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 disconnectevent, when it'll remove it from the map.

服务器开始在端口 8000 上侦听传入连接。当一个客户端到达时,它会将这个新客户端添加到地图中,以便它可以跟踪其序列号。它还侦听该客户端的disconnect事件,当它从地图中删除它时。

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.

每一秒,都会触发一个计时器。当它这样做时,服务器遍历映射并向每个客户端发送一条带有当前序列号的消息。然后它增加它并将数字存储回地图中。这就是它的全部内容。十分简单。

Client

客户

The client part is even simpler. It just connects to the server and listens for the seq-nummessage, 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.

我也准备与全电码梗概这里

回答by PHPthinking

In 1.0 you should use:

在 1.0 中,您应该使用:

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

回答by DecoderNT

You can use

您可以使用

//send message only to sender-client

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

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

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

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

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

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

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

//send to all listeners except the sender

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

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

socket.broadcast.emit('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('chatroom').emit('message', 'this is the message to all');

回答by Suman Barick

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.on('connection', function(socket) {...});] ,我们可以看到“io”只是一个json对象,并且有很多子对象存储了socket id和socket对象。

I am using socket.io version 1.3.5, btw.

我正在使用 socket.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,

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

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

回答by abhaygarg12493

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

回答by risuch

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。我正在使用客户端记录的 socketId 进行调试,它没有前缀,所以我最终一直搜索直到我发现!因此,如果您拥有的 Id 没有前缀,您可能必须这样做:

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

回答by aljosa

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

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