egg-websocket-plugin icon indicating copy to clipboard operation
egg-websocket-plugin copied to clipboard

请问下如何只给一个房间内的其他用户发送消息,而不给当前连接的客户端发送消息呢?

Open xwwxyd opened this issue 4 years ago • 18 comments

xwwxyd avatar Dec 01 '20 09:12 xwwxyd

@MrWWY 目前这个插件提供的都是比较底层的功能,可以通过如下的方式来实现

  1. 使用中间件为当前连接的 ctx 添加 uuid 来识别不同的连接
// 在 router.ts 中配置中间件
import { v4 as uuidv4 } from 'uuid';

// 将中间件安装放在所有 app.ws.use 之前,这样 app.ws.route 才会用上中间件
app.ws.use(async (ctx, next) => {
  // 使用 uuid 库不是必须的,可以根据实际系统中用户身份的唯一身份 ID 号来替换这个 uuid
  ctx.uuid = uuidv4();
  await next();
});
  1. 发送消息时,构造 JSON 消息
ctx.websocket.room.sendJsonTo('someroom', {from: ctx.uuid, ...})
  1. 加入房间时使用自定义房间消息处理函数 参考文档
ctx.websocket.room.join('someroom', ({ message }) => {
  const data = JSON.parse(message.toString());
  if (data && data.from === ctx.uuid) {
    console.log('发送者是自己');
    return;
  }
  // 将消息发送到当前连接
  this.ctx.websocket.send(message);
});

flarestart avatar Dec 03 '20 07:12 flarestart

只能以房间为单位,不能指定用户发送消息?

caihaibin1991 avatar Feb 20 '21 06:02 caihaibin1991

@caihaibin1991 由于 egg.js

是多进程的,因此不像其他服务器框架一样,可以在同一个进程上指定向某一个连接(用户)发送消息 向指定的用户发送消息,可以通过将每个用户加入一个与用户 ID 关联的房间名来实现

flarestart avatar Feb 24 '21 06:02 flarestart

嗯, 目前就是这么处理。谢谢哈

caihaibin1991 avatar Feb 24 '21 06:02 caihaibin1991

不过有点不是很理解,是走redis订阅发布,但是我启动4核,推送消息时,4个都能接收到,但是redis publish时确只显示推送了1个客户端. 然后我直接通过redis-cli subscribe channel, 再发布, 就有显示多一个...为啥?

caihaibin1991 avatar Feb 24 '21 06:02 caihaibin1991

不过有点不是很理解,是走redis订阅发布,但是我启动4核,推送消息时,4个都能接收到,但是redis publish时确只显示推送了1个客户端. 然后我直接通过redis-cli subscribe channel, 再发布, 就有显示多一个...为啥?

没太看明白,可以把具体的代码以及执行的命令行指令发出来,可以帮你看一下

redis 发布订阅本身就是一对多的关系,同一个消息会发送给多个消息订阅的接收者

flarestart avatar Feb 24 '21 07:02 flarestart

image

caihaibin1991 avatar Feb 24 '21 07:02 caihaibin1991

但是websocket确实都有收到消息.

caihaibin1991 avatar Feb 24 '21 07:02 caihaibin1991

redis-cli pubsub channels 可以显示所有通道,然后直接在cmd这边推送消息过去.

caihaibin1991 avatar Feb 24 '21 07:02 caihaibin1991

安利个超级神器:node-zone eggjs我这边是用midway这版本.

caihaibin1991 avatar Feb 24 '21 07:02 caihaibin1991

egg.js 的代码里面需要有加入 test 房间的代码,且需要有一个 WebSocket 客户端连接上 egg.js 服务器,再使用 redis 发送消息才会收到。插件不使用 room.join 方法时,并没有进行 Redis 的订阅操作

flarestart avatar Feb 24 '21 07:02 flarestart

@caihaibin1991 另外,直接用 redis 的 publish 向房间发送消息时,发送字符串需要加上前缀 s string 发送 Binary 类型需要第一个字节是 b binary。WebSocket 客户端收到的数据类型有所区别。

参考源代码 https://github.com/flarestart/egg-websocket-plugin/blob/master/adapter/redis.ts#L20-L31

flarestart avatar Feb 24 '21 07:02 flarestart

是有redis的,我eggjs这边开四个websocket,然后是通过cmd redis这边直接发送消息,浏览器这边是有实时显示的。四个都有。功能都没问题,就是不理解为什么redis这边发送后,只显示发送了一个....然后四个都能接收到....

caihaibin1991 avatar Feb 24 '21 07:02 caihaibin1991

@caihaibin1991 另外,直接用 redis 的 publish 向房间发送消息时,发送字符串需要加上前缀 s string 发送 Binary 类型需要第一个字节是 b binary。WebSocket 客户端收到的数据类型有所区别。

参考源代码 https://github.com/flarestart/egg-websocket-plugin/blob/master/adapter/redis.ts#L20-L31

有的。我是在cmd这边模拟了订阅,然后把接收到的消息再复制一份发回去.

caihaibin1991 avatar Feb 24 '21 07:02 caihaibin1991

@caihaibin1991 4 个WebSocket 客户端如果都是连接的同一个进程,这种情况下,只有一个进程在进行订阅 test 房间,一个进程只会建立唯一 Redis 连接,因此不管有多少个 WebSocket 客户端订阅了 test 房间,一个进程内的房间订阅插件实现都会优化成一个 Redis 底层连接

flarestart avatar Feb 24 '21 07:02 flarestart

@caihaibin1991 4 个WebSocket 客户端如果都是连接的同一个进程,这种情况下,只有一个进程在进行订阅 test 房间,一个进程只会建立唯一 Redis 连接,因此不管有多少个 WebSocket 客户端订阅了 test 房间,插件都会优化成一个 Redis 底层连接

确实,谢啦.

caihaibin1991 avatar Feb 24 '21 07:02 caihaibin1991

如何向指定客户端发送消息。比如我接收到一个http请求后决定向某个用户发送消息,如何指定用户呢

wangxiaogang94 avatar Jul 29 '21 12:07 wangxiaogang94

@wangxiaogang94 可以参考之前的回复来实现

flarestart avatar Aug 03 '21 09:08 flarestart