前言
网上查阅了 socket.io 官方文档,似乎没有发现最新的中文文档,有旧的,比如这个 (socket.io 中文文档) 是 2017 年的。
官网的实例和网上绝大多数入门例子,几乎都一样,就一个群聊窗口,过于简单。这让很多有志于socket.io 学习的人不那么方便,这里翻译一篇官网的 socket.io 关于 namespace 和rooms 的文档,希望对大家有点帮助。如需要查阅的人多,再考虑翻译其它节。
原文地址:Rooms and Namespaces
以下为译文
命名空间(namespace,以下简称ns)
socket.io 允许你将socket 制定不同的命名空间,本质上,就是指定不同的 终点(endpoint) 或 路径(path)
这是个有用的特性,它能减少所需资源数目(tcp 连接数),同时,它通过隔离通信信道(通道 channel)达到隔离应用的多个部分
默认命名空间
我们使用默认命名空间 / ,它既是socket.io 客户端默认连接也是服务端默认监听的的命名空间。
ns 通过 io.sockets 或 简以 io 调用加以区分:
// the following two will emit to all the sockets connected to `/`
io.sockets.emit('hi', 'everyone');
io.emit('hi', 'everyone'); // short form
每个ns 都会触发一 connection 事件,并以 socket 作为参数传递到事件响应中
io.on('connection', function(socket){
socket.on('disconnect', function(){ });
});
自定义命名空间
如果要设置一个自定义ns,你可再服务端调用 of 函数:
const nsp = io.of('/my-namespace');
nsp.on('connection', function(socket){
console.log('someone connected');
});
nsp.emit('hi', 'everyone!');
在客户端,你可以告知 socket.io 客户端连接到对应的nsconst socket = io('/my-namespace');
重要提示:ns 仅是 socket.io 协议的实现细节,它和实际 URL 所表示的底层传输并无关系,如: /socket.io/...
房间(rooms)
在每个ns 内,你可以定义专属通道供, 这些sockets 可以 join 和 leave
Joining and leaving
你可以通过调用 join 函数 让 socket 订阅一个指定通道
io.on('connection', function(socket){
socket.join('some room');
});
然后,在广播或者分发时可以简单的使用 to 或者 in (两者等同)io.to('some room').emit('some event');
如果要离开通道,你可以像调用 join一样而调用 leave。 这两个方法都是异步的,接受 callback 作用参数
默认房间
在socket.io中,每个socket都会以一个 随机的、不可测的唯一标识 socket#id 区分。 为了方便,每个socket又会自动的通过这个标识id加入到一个房间。
这样让广播一个消息到其它sockets 很方便:
io.on('connection', function(socket){
socket.on('say to someone', function(id, msg){
socket.broadcast.to(id).emit('my message', msg);
});
});
断开连接(disconnection)
对应连接断开,socket 或自动的 leave 所有通道,并不需要你做其它处理
从外部发送消息
有时,你可能需要在socket.io 进程上下文之外向你的 socket.io ns / rooms 中的sockets 分发事件
有一些方式可以处理这种问题,比如实现自己的通道从而向进程发送消息
为了简化此种情况,我们创建了两个模块
- socket.io-redis
- socket.io-emitter
通过实践redis 适配器:
const io = require('socket.io')(3000);
const redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
然后你就能从其他进程 emit 消息到任意通道
const io = require('socket.io-emitter')({ host: '127.0.0.1', port: 6379 });
setInterval(function(){
io.emit('time', new Date);
}, 5000);
以上为翻译全文
后记
幸好本节不长内容不多,翻译一个小时左右。对于文章尾部 “从进程外发送消息”,这个例子和说明不是很清晰,这里再补充下:
socket.io-redis 和 socket.io-emitter 是两个独立的模块,它们并不一定要组合使用。
对于实际的生产环境,我们的socket.io 服务可能是集群部署,使用多个进程或者在多个服务器,在某一进程 emit 如何让其它进程上的客户端也能收到? 此时 socket.io-redis 就是一有效工具,它通过 redis本身自带的 Pub/Sub 机制,达到也向其它进程上的客户端广播消息的目的。
而 socket.io-emmitter 才是完全从其它非socket.io 进程发送消息到socket.io 进程所要依赖的,同时结合 socket.io-redis 使用。