分类
技术

WebSocket 如何实现服务端向客户端发送消息?

我们都知道, Websocket 是一个双向的通讯方式,一般情况下,我们都是根据 Client 的情况返回信息,但是在一个更加健壮的系统,我们可能需要主动的向客户端发送消息。我试图在中文网络去搜索,查找相关信息,无果。因此便开始搜索英文世界中的内容。如今已经实现我想要的需求,便写一篇文章分享一下。

需求

需求是 Websocket 服务端作为中心控制服务器,会对外提供一个 RESTFul API,其他部件通过 RESTFul API 来链接 WebSocket 服务端发起请求,由 WebSocket 服务端进行设备相关的控制。

实现

首先,前提是我们的服务端和设备端是保持着 websocket 的长链接操作的,那么,我们在 RESTFul 中只要获取到这个链接,就可以发送消息了。

而 websocket 中,我们如果想要获取到一个特定的链接,就需要使用 websocket 的 socket.id 来完成我们的需求。这就要求我们提前将 socket.id 存储起来,这样当我们需要的时候,我们就可以直接拿 socket.id 来发送消息。

在 Socket.io 中,你需要使用 io.sockets.connected[socketID].emit(“greeting”, “Howdy, User 1!”); 来发送消息。

在 egg.js 中,则是 app.io.sockets.connected[socketID].emit(‘res’, ‘send From app’);

有了这个代码,你就可以实现在 RESTFul API 中向 Client 中发送消息了。

参考代码

说明

本例中使用的是 Socket.io + Egg.js 实现的

服务端代码

//config/config.default.js
config.io = {
    namespace: {
      '/': {
        connectionMiddleware: [ 'auth' ],
        packetMiddleware: [],
      },
    },
  };
// app/io/middleware/auth.js
'use strict';

module.exports = () => {
  return async (ctx, next) => {
    const { socket, app } = ctx;
    const id = socket.id; // 获取 Socket ID
    app.redis.set('pid', id); // 设置 Socket ID
    ctx.socket.emit('res', `Your id is ${id}`);
    await next();
  };
};
// app/controller/home.js
'use strict';

const Controller = require('egg').Controller;

class HomeController extends Controller {
  async send() {
    const { ctx, app } = this;
    const id = await app.redis.get('pid'); // 获取 ID
    app.io.sockets.connected[id].emit('res', 'send From app');// 发送数据
    ctx.body = 'ok';
  }
}

module.exports = HomeController;

参考文章

https://michaelheap.com/sending-messages-to-certain-clients-with-socket-io/

由Bestony

发表评论