用socket.io和node.js发送消息给特定的客户端

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

client.send(message, receiverSessionId) 

但是.send().broadcast()方法都不能满足我的需求。

我发现作为一个可能的解决scheme,是.broadcast()方法接受作为第二个参数的SessionIds数组不发送消息,所以我可以传递一个数组与所有SessionIds连接到服务器,除了我希望发送的信息之外,我觉得必须有更好的解决办法。

有任何想法吗?

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

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

这可能会破坏,我很难怀疑它,但是io.clients可能会改变,所以请谨慎使用

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

我会使用后者,因为根据您的应用程序,您可能希望有更多的客户端状态,所以像clients[id] = {conn: clientConnect, data: {...}}可能会做工作。

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

每个套接字都join一个带套接字ID的房间作为名字,所以你可以

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

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

干杯

最简单,最优雅的解决scheme

这很简单:

 client.emit("your message"); 

就是这样。

但是,如何? 给我举个例子

我们都需要的是一个完整的例子,接下来就是这个例子。 这是testing与最新的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); 

服务器开始在端口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 npm install socket.io-client 

运行服务器:

 node server 

打开其他terminal窗口,通过运行生成尽可能多的客户端:

 node client 

我也在这里准备了完整的代码。

在1.0中你应该使用:

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

您可以使用

//发送消息只发送给客户端

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

无论我们使用的是什么版本,如果我们只是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] }, 

在这里我们可以看到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(); 

所以,我想我们可以用上面列出的三种方法来实现我们的目标,

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

你可以这样做

在服务器上。

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

从版本1.4.5开始,确保在io.to()中提供正确的前缀socketId。 我正在把socketId客户端logging到debugging,它是没有前缀,所以我结束了search,直到我发现了! 所以你可能需要这样做,如果你有一个ID没有前缀:

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

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

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

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