Node.js+Socket.io实现广播功能

一、简介

用socket.io+Node实现一个房间内广播的功能,原本以为API会有类似的功能,虽然目前来看会有比较相近的功能,但是效果依然不尽人意,故自己琢磨了一下该方面的实现过程。

当前使用的包的信息如下:

包/软件版本说明
Nodev12.15.0
socket.iov3.1.0socket服务器
socket.io-clientv3.1.0socket客户端

二、一个基础的连接例子

先上一个最基础的client连接server端的例子。

  • server端代码
const { Server } = require('socket.io');

// 将socket服务器监听3001端口
const io = new Server(3001);

// 监听客户端连接上的事件
io.on('connection', (socket) => {
  console.log(`${socket.id} connected`);
});
  • client端代码
const io = require('socket.io-client');

const socket = io('http://127.0.0.1:3001');

// client端连接上server端的事件
socket.on('connect', () => {
  console.log('client connect');
});

可以看到控制台中:

  • server端输出:mY28QxO5iF557kdBAAAD connected
  • client端输出:client connect

三、普通广播

3.1 全广播

基于上面基础的例子,在server端代码中connection事件中添加一个广播操作,并且在client端代码中添加对message事件的监听。

  • server端代码
const { Server } = require('socket.io');

// 将socket服务器监听3001端口
const io = new Server(3001);

// 监听客户端连接上的事件
io.on('connection', (socket) => {
  console.log(`${socket.id} connected`);
  
  // 广播
  io.sockets.send('This is a broadcast message');
});
  • client端代码
const io = require('socket.io-client');

const socket = io('http://127.0.0.1:3001');

// client端连接上server端的事件
socket.on('connect', () => {
  console.log('client connect');
});

// 添加对message事件的监听
socket.on('message', (msg) => {
  // 打印msg
  console.log(`receive message ${msg}`)
});

当client连接上server后,server将会广播一条This is a broadcast message消息给连接到该server的所有client。大致逻辑如下:

  • A、B为客户端,C为服务器
  • 当A连接上C后,C将会给A发送一条消息
  • 当B连接上C后,C将会给A和B各发送一条消息

3.2 部分广播

上面的全广播代表会将消息发送给每一个连接到server端的client,包括自己。但是某些时候可能只需要发送给一部分client,比如发送除了自己之外的其他client。此时,就需要将所有连接上的client进行遍历,然后依次使用send方法。

所有的部分广播只有server端代码会有所不同,client端代码依旧保持原样。

  • server端代码
const { Server } = require('socket.io');

// 将socket服务器监听3001端口
const io = new Server(3001);

// 监听客户端连接上的事件
io.on('connection', (socket) => {
  console.log(`${socket.id} connected`);
  
  // 获取所有连接上来的client
  const sockets = io.sockets.sockets;
  
  // 遍历所有client,依次使用send方法发送,并且根据ID剔除自身
  for (client of sockets) {
    if (client[0] !== socket.id) {
      socket[1].send('this is a broadcast message');
    }
  }
});

四、Namespace+广播

4.1 全广播

如果想给client划分一下,有个“分组”之类的概念,则可以使用namespace特性。

之前没有使用namespace特性时,我们是直接使用的io,现在使用了namespace特性后,需要针对特定的namespace进行操作的话,需要使用io.of('/my_namespace')。且类似io.sockets这样的代码也无需加上socketsflag了。

  • server端代码
const { Server } = require('socket.io');

// 将socket服务器监听3001端口
const io = new Server(3001);
const NAME_SPACE_1 = '/my_namespace';

// 注意这里要使用of+namespace,否则无法监听到client连接到对应namespace事件
io.of(NAME_SPACE_1).on('connection', (socket) => {
  console.log(`${socket.id} connected ${NAME_SPACE_1}`);
  
  // 注意此处
  io.of(NAME_SPACE_1).send('This is a broadcast message');
});

// 再添加一个namespace
const NAME_SPACE_2 = '/other';
io.of(NAME_SPACE_2).on('connection', (socket) => {
  console.log(`${socket.id} connected ${NAME_SPACE_2}`);
  
  // 注意此处
  io.of(NAME_SPACE_2).send('This is a broadcast message from' + NAME_SPACE_2);
});
  • client端代码
    client端代码首要解决任务是连接到对应的namespace中。该namespace需要在连接的url处进行制定。
const io = require('socket.io-client');

const NAME_SPACE_1 = '/my_namespace';
const socket = io('http://127.0.0.1:3001' + NAME_SPACE_1);

// client端连接上server端的事件
socket.on('connect', () => {
  console.log('client connect ' + NAME_SPACE_1);
});

// 添加对message事件的监听
socket.on('message', (msg) => {
  // 打印msg
  console.log(`receive message ${msg}`)
});

同样的,这里也是对连接到对应namespace下的所有client进行广播。
逻辑如下:

  • A、B为客户端,C为服务器
  • A连接到C名为/my_namespace的namespace
  • C将会对名为/my_namespace下的所有客户端发送信息,包括A
  • B连接到C名为/other的namespace
  • C将会对名为/other下的所有客户端发送信息,包括B,不包括A

4.2 部分广播

  • server端代码
const { Server } = require('socket.io');

// 将socket服务器监听3001端口
const io = new Server(3001);
const NAME_SPACE_1 = '/my_namespace';

// 这里只用一个namespace来进行展示,其余的也是相同的
io.of(NAME_SPACE_1).on('connection', (socket) => {
  console.log(`${socket.id} connected ${NAME_SPACE_1}`);
  
  // 获取全部sockets
  const sockets = io.of(NAME_SPACE_1).sockets;

  // 遍历sockets,
  for (client of sockets) {
    if (client[0] !== socket.id) {
      client[1].send('this is a broadcast message');
    }
  }
});

五、room+广播

5.1 全广播

如果认为namespace不是很灵活,不能随时切换分组的话,可以考虑使用room概念。room概念的话,允许一个client同时加入多个room,且允许随时离开、加入,而无需重新建立连接。

  • server端代码
const { Server } = require('socket.io');

// 将socket服务器监听3001端口
const io = new Server(3001);
const ROOM = 'my_room';

// 监听客户端连接上的事件
io.on('connection', (socket) => {
  // 首先要让socket加入某一房间
  socket.join(ROOM);
  
  console.log(`${socket.id} connected room ${ROOM}`);
  
  // 广播
  io.in(ROOM).send('This is a room broadcast message');
});
  • client端代码
const io = require('socket.io-client');

const socket = io('http://127.0.0.1:3001')
socket.on('connect', () => {
  console.log('client connect')
});

socket.on('message', (data) => {
  console.log('receive message ' + data);
});

5.2 部分广播

  • server端代码
const { Server } = require('socket.io');

// 将socket服务器监听3001端口
const io = new Server(3001);
const ROOM = 'my_room';

// 监听客户端连接上的事件
io.on('connection', (socket) => {
  // 首先要让socket加入某一房间
  socket.join(ROOM);
  
  console.log(`${socket.id} connected room ${ROOM}`);

  // 获取全部sockets
  const sockets = io.in(ROOM).sockets.sockets;

  // 遍历
  for (client of sockets) {
    if (client[0] !== socket.id) {
      client[1].send('This is a room broadcast message')
    }
  }
});

六、小结

以上就是socket.io几种广播的方式,当然也只是普通的广播,还没有做到剔除当前连接对象,只广播给其他的client,这部分内容我将考虑在之后更新上来,欢迎大家继续关注。

总结一下几种广播的区别吧

广播名称特性
普通广播无法进行分组广播,只要连接上来的都会广播到(其实会和namespace有区分,因为普通广播的namespace为/),不过也仅此而已了
namespace广播会让client根据自己所要连接的namespace进行分组广播,缺点就是不能灵活切换
room广播允许client灵活的变更room,这是优点,也是缺点,在复杂的逻辑环境下,room过于灵活的变更反而不利于管理

文章若有不妥之处,欢迎大家斧正~

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值