Socket.io + Redis-客户正在加入彼此的“私人”房间

时间:2018-06-21 18:05:24

标签: node.js redis socket.io

我刚刚开始使用Socket.io和Redis进行发布/订阅消息传递,这非常棒。我的应用程序的一个重要功能是服务器需要能够向一个房间的所有订户广播消息,并且还必须选择该房间中的1个订户并仅向他们窄播一条消息。现在,该订户是随机选择的。基于阅读socket.io的文档,我认为我可以完成这项工作。

但是,我遇到了一些我不理解的东西。在Socket.io的默认会议室文档(https://socket.io/docs/rooms-and-namespaces/#default-room)中,他们说每个套接字都自动加入以其套接字ID命名的会议室。看来这可以解决我的窄播要求-查看连接到我的“大”房间的客户端ID列表,随机选择一个,然后向该房间发送与所选ID同名的消息。

但是,它不起作用,因为由于某些原因,所有客户端都加入了彼此的默认房间。我的代码中没有看到任何异常,但是我的“窄播”消息将发送给所有客户端。

这是我的服务器端代码:

var io = require('socket.io');
var redisAdapter = require('socket.io-redis');
var server = io();

server.adapter(redisAdapter({ host: 'localhost', port: 6379 }))

server.on('connect', (socket) => {
  console.log(`${socket.id} connected!`);
  socket.join('new');
  server.emit('welcome', `Please give a warm welcome to ${socket.id}!`);
  server.to(socket.id).emit('private', 'Just between you and me, I think you are going to like it here');
});

server.listen(3000);

setInterval(whisperAtRandom, 2000);

function whisperAtRandom() {
  server.in('new').adapter.clients((err, clients) => {
    if (err) throw err;

    console.log('Clients on channel "new": ', clients);
    chosenOne = clients[Math.floor(Math.random()*clients.length)];
    console.log(`Whispering to ${chosenOne}`);
    server.to(chosenOne).emit('private', { message: `Psssst... hey there ${chosenOne}`});
    server.in(chosenOne).adapter.clients((err, clients) => {
      console.log(`Clients in ${chosenOne}: ${clients}`)
    })
  });
}

它站立在服务器上,侦听端口3000,然后每2秒向“新”房间中的随机客户端发送一条消息。它还注销了连接到“新”会议室和“”会议室的客户端列表。

这是客户端代码:

var sock = require('socket.io-client')('http://localhost:3000');

sock.connect();

sock.on('update', (data) => {
  console.log('Updating...');
  console.log(data);
});

sock.on('new', (data) => {
  console.log(`${sock.id} accepting request for new`);
  console.log(data.message);
});

sock.on('welcome', (data) => {
  console.log('A new challenger enters the ring');
  console.log(data);
});

sock.on('private', (data) => {
  console.log(`A private message for me, ${sock.id}???`);
  console.log(data);
});

我的问题是我所有的客户都连接到彼此的房间。这是我的日志中的一个示例:

0|socket-s | Clients on channel "new":  [ 'dJaoZd6amTfdQy5NAAAA', 'bwG1yTT46dr5R_G6AAAB' ]
0|socket-s | Whispering to bwG1yTT46dr5R_G6AAAB
2|socket-c | A private message for me, dJaoZd6amTfdQy5NAAAA???
2|socket-c | Psssst... hey there bwG1yTT46dr5R_G6AAAB
1|socket-c | A private message for me, bwG1yTT46dr5R_G6AAAB???
1|socket-c | Psssst... hey there bwG1yTT46dr5R_G6AAAB
0|socket-s | Clients in bwG1yTT46dr5R_G6AAAB: dJaoZd6amTfdQy5NAAAA,bwG1yTT46dr5R_G6AAAB

您可以看到dJaoZ...bwG1y...这两个客户端都收到了“私人”消息,并且两个客户端都连接到bwG1y...的默认房间。

这是为什么?我的两个客户端都在同一台计算机上运行(具有不同的Node进程),这是否与事实有关?我在Socket.io的文档中缺少什么吗?任何帮助表示赞赏!

PS -更令人困惑的是,server.on('connect', ...中发生的私人消息传递有效!每个客户端在连接到服务器之后,都会收到一次“您和我之间...之间的消息”。

1 个答案:

答案 0 :(得分:1)

您的主要问题可能是由server.to函数中的whisperAtRandom引起的,对于私人消息,请使用套接字而不是服务器:

socket.to(chosenOne).emit('private', { message: `Psssst... hey there ${chosenOne}`});

要回答您的其他问题,请尝试更改以下问题:

server.emit('welcome', `Please give a warm welcome to ${socket.id}!`);
server.to(socket.id).emit('private', 'Just between you and me, I think you are going to like it here');

收件人:

socket.broadcast.emit('welcome', `Please give a warm welcome to ${socket.id}!`);
socket.emit('private', 'Just between you and me, I think you are going to like it here');

查看我的Socket.IO速查表:

// Socket.IO Cheatsheet

// Add socket to room
socket.join('some room');

// Remove socket from room
socket.leave('some room');

// Send to current client
socket.emit('message', 'this is a test');

// Send to all clients include sender
io.sockets.emit('message', 'this is a test');

// Send to all clients except sender
socket.broadcast.emit('message', 'this is a test');

// Send to all clients in 'game' room(channel) except sender
socket.broadcast.to('game').emit('message', 'this is a test');

// Send to all clients in 'game' room(channel) include sender
io.sockets.in('game').emit('message', 'this is a test');

// sending to individual socket id
socket.to(socketId).emit('hey', 'I just met you');