Socket.io双向通信教程,如何理解使用命名空间?
发布于 作者:苏南大叔 来源:程序如此灵动~

默认情况下,socket.io
的代码中,是不体现命名空间的,或者说命名空间就是/
。如果代码日益复杂,增加命名空间就有必要性了。命名空间的作用,就类似苏南大叔的博客文章链接一样,使用路径目录来作为文章链接的命名空间。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。测试环境:win10
,nodejs@20.18.0
,express@4.21.2
,socket.io@4.8.1
。
前文回顾
在socket.io
的路径及跨域相关的话题里面,就有提到在客户端初始化的时候,可以传递服务端地址。如果在这个地址后面加上一个目录的话,就是个命名空间了。
- https://newsn.net/say/socket-io.html
- https://newsn.net/say/socket-io-path.html
- https://newsn.net/say/socket-io-transport.html
- https://newsn.net/say/socket-io-broadcast.html
- https://newsn.net/say/socket-io-cors.html
客户端代码
基本版,不带命名空间:
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
//...
</script>
带命名空间:
const socket = io("/sunan");
const socket = io("ws://localhost:3000/sunan");
const socket = io("http://localhost:3000/sunan");
服务端代码
就是在原来的io
后面加个.of()
就是命名空间了。
//...
const socketio = require("socket.io");
const io = socketio(expressServer);
io.of("/sunan").on("connection", (socket) => {
//...
});
测试代码
这个例子里面,一共两个命名空间,
- 分别是
/milk
和/beer
,对应两个产品线。 - 房间并不是单独的存在,它隶属于某个命名空间。
io.of().to()
,只能向它名下的房间发消息。
客户端:
业务(namespace):<select id="namespace" onchange="switch__io(this.value)">
<option value="/">默认</option>
<option value="/milk">牛奶(/milk)</option>
<option value="/beer">啤酒(/beer)</option>
</select>
分组(room):<select id="room" onchange="join(this.value)">
<option value="0">--</option>
<option value="1">绩效监控组</option>
<option value="2">碌碌无为组</option>
</select>
<button onclick="go(1)">业务代码(+1)</button>
<button onclick="go(3)">业务代码(+3)</button>
<script src="/socket.io/socket.io.js"></script>
<script>
let namespaces = document.getElementById('namespace');
let all_io = [];
for (let i = 0; i < namespaces.options.length; i++) {
const _io = io(namespaces.options.item(i).value);
_io.on('message', message => {
console.log(message);
});
all_io.push(_io);
}
let current_io = all_io[0];
function switch__io(namespace) {
current_io = all_io.find(io => io.nsp === namespace);
document.getElementById('room').value = '0'; // Reset room dropdown to default
}
function go(num) {
current_io.emit('message', num);
}
function join(room) {
// all_io[0].emit('join', room);
current_io.emit('join', room);
}
</script>
服务端:
let express = require("express");
let app = express();
app.use(express.static('public'));
let expressServer = app.listen(80, () => console.log('http://localhost:%s', expressServer.address().port));
const socketio = require("socket.io");
const io = socketio(expressServer);
io.on("connection", (socket) => {
socket.on("join", (room) => {
room = parseInt(room) || 0;
socket.leave(1);
socket.leave(2);
if (room > 0) {
socket.join(room);
io.to(socket.id).emit("message", "欢迎" + socket.id + "加入房间" + room);
console.log("加入房间" + room);
}
});
socket.on("message", (msg) => {
console.log("收到消息:" + msg);
io.to(1).emit("message", "监控消息:"+socket.id + "卖了" + msg + "单");
});
});
io.of("/milk").on("connection", (socket) => {
socket.on("join", (room) => {
room = parseInt(room) || 0;
socket.leave(1);
socket.leave(2);
if (room > 0) {
socket.join(room);
}
});
socket.on("message", (num) => {
io.emit("message", "全体广播:牛奶组" + socket.id + "出了" + num + "单");
io.of("/beer").emit("message", "啤酒组发来全局贺电");
io.of("/milk").to(1).emit("message", "监控消息:" + socket.id + "卖了牛奶" + num + "单");
});
});
io.of("/beer").on("connection", (socket) => {
socket.on("join", (room) => {
room = parseInt(room) || 0;
socket.leave(1);
socket.leave(2);
if (room > 0) {
socket.join(room);
}
});
socket.on("message", (num) => {
io.emit("message", "全体广播:啤酒组" + socket.id + "出了" + num + "单");
io.of("/milk").emit("message", "牛奶组发来全局贺电");
io.of("/beer").to(1).emit("message", "监控消息:" + socket.id + "卖了啤酒" + num + "单");
});
});
结语
更多苏南大叔的socket
经验文章,请参考:


