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

Rod*_*lma 179 javascript server-side websocket node.js socket.io

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

client.send(message, receiverSessionId)
Run Code Online (Sandbox Code Playgroud)

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

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

有任何想法吗?

Epe*_*eli 171

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

});
Run Code Online (Sandbox Code Playgroud)

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

  • 谢谢它很有帮助.我只需要使用一个数组:`io.of('/ mynamespace').sockets [socketID] .emit(...)`(不知道是不是因为我正在使用命名空间) (4认同)
  • ```io.sockets.socket(socket_id)``` 在 socket.io 1.0 中被移除。https://github.com/socketio/socket.io/issues/1618#issuecomment-46151246 (2认同)

Ivo*_*zel 93

那么你必须抓住客户端(惊喜),你可以采取简单的方式:

var io = io.listen(server);
io.clients[sessionID].send()
Run Code Online (Sandbox Code Playgroud)

这可能会破坏,我几乎不怀疑,但它总是有io.clients可能被改变,所以请谨慎使用上述内容

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

我会使用后者,因为根据你的应用程序,你可能希望在客户端有更多的状态,所以类似的事情clients[id] = {conn: clientConnect, data: {...}}可能会起作用.

  • 伊沃,你能指出一个更完整的例子或精心制作一下吗?我很想理解这种方法,但我不确定我是否认识到你在这个例子中使用的变量/对象.在客户端[id] = {conn:clientConnect,data:{...}}中,客户端[id]是io对象的一部分,如上面的io.clients [sessionID]所示?什么是clientConnect对象?谢谢. (5认同)

小智 88

每个套接字都加入一个带有套接字id的房间作为名称,所以你可以

io.to(socket#id).emit('hey')
Run Code Online (Sandbox Code Playgroud)

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

干杯

  • 这是最好的答案,适用于较新版本的socket.io.这里有一个很好的备忘单:http://stackoverflow.com/questions/10058226/send-response-to-all-clients-except-sender-socket-io (6认同)
  • 请注意,这是一种发送事件的"广播"类型.因此,如果您尝试设置回调,则会出现错误.如果你需要通过回调将事件发送到特定的套接字,那么使用@ PHPthinking的答案并使用``io.sockets.connected [socketid] .emit();``.测试1.4.6. (4认同)

Luc*_*iva 77

最简单,最优雅的解决方案

它很简单:

client.emit("your message");
Run Code Online (Sandbox Code Playgroud)

就是这样.

但是怎么样?举个例子

我们所有人都需要的是一个完整的例子,接下来就是这样.这是使用最新的socket.io版本(2.0.3)测试的,它也使用现代Javascript(我们现在应该全部使用它).

该示例由两部分组成:服务器和客户端.每当客户端连接时,它就开始从服务器接收周期性序列号.为每个新客户端启动一个新序列,因此服务器必须单独跟踪它们.这就是"我需要向特定客户发送消息"的地方.代码很容易理解.让我们来看看它.

服务器

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);
Run Code Online (Sandbox Code Playgroud)

服务器开始在端口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));
Run Code Online (Sandbox Code Playgroud)

运行示例

安装所需的库:

npm install socket.io
npm install socket.io-client
Run Code Online (Sandbox Code Playgroud)

运行服务器:

node server
Run Code Online (Sandbox Code Playgroud)

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

node client
Run Code Online (Sandbox Code Playgroud)

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


小智 33

在1.0中你应该使用:

io.sockets.connected[socketid].emit();
Run Code Online (Sandbox Code Playgroud)

  • 这可能是因为 api 更新了,并且不再有像 `io.sockets.connected["something"]` 和它的 `emit` 方法这样的对象。 (2认同)

Dec*_*rNT 31

您可以使用

//仅向sender-client发送消息

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


Sum*_*ick 12

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

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

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

 sockets:
  { name: '/',
    server: [Circular],
    sockets: [ [Object], [Object] ],
    connected:
     { B5AC9w0sYmOGWe4fAAAA: [Object],
       'hWzf97fmU-TIwwzWAAAB': [Object] },
Run Code Online (Sandbox Code Playgroud)

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

io.sockets.connected[socketid].emit();
Run Code Online (Sandbox Code Playgroud)

再次,在进一步检查时,我们可以看到像

 eio:
  { clients:
     { B5AC9w0sYmOGWe4fAAAA: [Object],
       'hWzf97fmU-TIwwzWAAAB': [Object] },
Run Code Online (Sandbox Code Playgroud)

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

io.eio.clients[socketid].emit();
Run Code Online (Sandbox Code Playgroud)

另外,在引擎下我们有,

engine:
 { clients:
    { B5AC9w0sYmOGWe4fAAAA: [Object],
      'hWzf97fmU-TIwwzWAAAB': [Object] },
Run Code Online (Sandbox Code Playgroud)

所以,我们也可以写,

io.engine.clients[socketid].emit();
Run Code Online (Sandbox Code Playgroud)

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

  1. io.sockets.connected [socketid] .emit(); 要么
  2. io.eio.clients [socketid] .emit(); 要么
  3. io.engine.clients [socketid] .emit();


abh*_*493 11

你可以这样做

在服务器上.

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 "});
    }
Run Code Online (Sandbox Code Playgroud)

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

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)
    })
Run Code Online (Sandbox Code Playgroud)


小智 6

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


小智 6

从版本1.4.5开始,请确保在io.to()中提供了正确的前缀socketId.我正在接受socketId客户端登录调试,它没有前缀所以我最终搜索永远直到我发现!如果您拥有的ID没有前缀,那么您可能必须这样做:

io.to('/#' + socketId).emit('myevent', {foo: 'bar'});
Run Code Online (Sandbox Code Playgroud)