提问人:Rodolfo Palma 提问时间:1/10/2011 最后编辑:Lucio PaivaRodolfo Palma 更新时间:12/24/2022 访问量:346379
使用 socket.io 和node.js向特定客户端发送消息
Send message to specific client with socket.io and node.js
问:
我正在使用 socket.io 和 node.js,直到现在它看起来还不错,但我不知道如何从服务器向特定客户端发送消息,如下所示:
client.send(message, receiverSessionId)
但这两种方法似乎都不能满足我的需求。.send()
.broadcast()
我发现一个可能的解决方案是,该方法接受一个不向其发送消息的 SessionIds 数组作为第二个参数,因此我可以将一个包含当时连接的所有 SessionId 的数组传递给服务器,除了我希望发送消息的那个,但我觉得必须有更好的解决方案。.broadcast()
有什么想法吗?
答:
好吧,你必须抓住客户(惊喜),你可以走简单的方法:
var io = io.listen(server);
io.clients[sessionID].send()
我对此表示怀疑,这可能会中断,但总是有可能被更改,因此请谨慎使用上述内容io.clients
或者你自己跟踪客户端,因此你把它们添加到侦听器中你自己的对象中,并在侦听器中删除它们。clients
connection
disconnect
我会使用后者,因为根据您的应用程序,您可能希望在客户端上拥有更多状态,因此类似的东西可能会完成这项工作。clients[id] = {conn: clientConnect, data: {...}}
评论
Ivo Wetzel 的答案似乎在 0.9 Socket.io 不再有效。
简而言之,您现在必须保存并用于向其发送消息。socket.id
io.sockets.socket(savedSocketId).emit(...)
这就是我在集群Node.js服务器中工作的方式:
首先,您需要将 Redis 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);
});
});
});
我在这里省略了聚类代码,因为它使它更加混乱,但添加起来很简单。只需将所有内容添加到工作线程代码中即可。更多文档请点击此处 http://nodejs.org/api/cluster.html
评论
io.of('/mynamespace').sockets[socketID].emit(...)
io.sockets.socket(socket_id)
在 socket.io 1.0 中删除。github.com/socketio/socket.io/issues/1618#issuecomment-46151246
io.sockets.sockets[socket.id].emit(...) 在 v0.9 中对我有用
评论
最简单、最优雅的方式
经验证可与 socket.io v3.1.1 配合使用
就这么简单:
client.emit("your message");
就是这样。好的,但它是如何工作的?
最小工作示例
下面是一个简单的客户端-服务器交互示例,其中每个客户端定期收到包含序列号的消息。每个客户端都有一个唯一的序列,这就是“我需要向特定客户端发送消息”发挥作用的地方。
服务器
server.js
const
{Server} = require("socket.io"),
server = new Server(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 [email protected] [email protected]
运行服务器:
node server
打开其他终端窗口,并通过运行以下命令生成任意数量的客户端:
node client
我还在这里准备了一个包含完整代码的要点。
评论
在 1.0 中,您应该使用:
io.sockets.connected[socketid].emit();
评论
io.sockets.connected["something"]
emit
每个套接字都加入一个带有套接字 ID 作为名称的房间,因此您可以只
io.to('socket#id').emit('hey')
文档:http://socket.io/docs/rooms-and-namespaces/#default-room
评论
io.sockets.connected[socketid].emit();
Socket.IO 允许您“命名”套接字,这实质上意味着分配不同的终结点或路径。
这可能会有所帮助:http://socket.io/docs/rooms-and-namespaces/
无论我们使用什么版本,如果我们只是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] },
在这里我们可以看到套接字ids“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();
所以,我想我们可以通过我上面列出的 3 种方式中的任何一种来实现我们的目标,
- 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)
})
你可以使用
仅向发件人客户端发送消息
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');
评论
从版本 1.4.5 开始,请确保在 io.to() 中提供正确前缀的 socketId。 我正在使用客户端记录的socketId进行调试,它没有前缀,所以我最终一直在搜索,直到我发现!因此,如果您拥有的 Id 没有前缀,您可能必须这样做:
io.to('/#' + socketId).emit('myevent', {foo: 'bar'});
评论
此外,您还可以保留客户引用。但这会让你的记忆很忙。
创建一个空对象并将客户端设置到其中。
const myClientList = {};
server.on("connection", (socket) => {
console.info(`Client connected [id=${socket.id}]`);
myClientList[socket.id] = socket;
});
socket.on("disconnect", (socket) => {
delete myClientList[socket.id];
});
然后通过对象的 ID 调用特定客户端
myClientList[specificId].emit("blabla","somedata");
上一个:为什么客户端验证还不够?
评论