用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();
所以,我想我们可以用上面列出的三种方法来实现我们的目标,
- io.sockets.connected [socketid] .emit(); 要么
- io.eio.clients [socketid] .emit(); 要么
- 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/