我们都知道, 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: [],
},
},
};
Code language: JavaScript (javascript)
// 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();
};
};
Code language: JavaScript (javascript)
// 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;
Code language: JavaScript (javascript)
参考文章
https://michaelheap.com/sending-messages-to-certain-clients-with-socket-io/