原文地址:https://socket.io/docs/rooms-and-namespaces/

Namespace

Socket.IO允许你与把sockets加入到某个命名空间中,这实际上就是为那些sockets分配不同的端点(endpoint)或路径(path)。

对于最小化资源(TCP连接)的数量来说,这是一个有用的特性。同时,通过引入对不同通讯频道的分离,可以分离我们的应用程序的关注点。

默认的命名空间

我们把 / 作为默认的命名空间,它是一个Socket.IO客户端默认会连接到的命名空间,还有就是它是Socket.IO服务器端默认监听的命名空间。

我们可以用 io.sockets (或者简写成 io) 来标识这个默认的命名空间。

// 下面的这两个例子都会发射'hi'事件给所有连接到默认命名空间'\'的socket们
io.socket.emit('hi', 'everyone');
io.emit('hi', 'everyone'); // 简写

当有socket连接到某个命名空间的时候,那个命名空间会发射一个 connection 事件,并用 Socket 实例作为参数,因此,服务器端可以通过监听 connection 事件来获取socket实例。

io.on('conncetion', function(socket) {
  console.log('someone connected');
  // 监听'disconnect'事件
  socket.on('disconnect', function(){ 
    // ...        
  });
});

自定义命名空间

在服务器端,我们可以用 of 函数来创建自定义的命名空间。

var nsp = io.of('/my-namespace');  // 创建自定义命名空间'/my-namespace'
// 监听'connection'事件
nsp.on('connection', function(socket) {
  console.log('someone connected');
});
nsp.emit('hi', 'everyone!');

在客户端,你可以让Socket.IO客户端去连接自定义命名空间’/my-namespace’:

var socket = io('/my-namespace');  // 这一句里面包含了发射  ``connection`` 事件

重要提醒: 命名空间是Socket.IO协议的实现细节,并且与底层传输的实际URL无关,默认为/socket.io/…。(因此,在客户端中都要包含一下代码,来引入从服务器传输过来的信息:)

<scirpt src="/socket.io/socket.io.js"></scirpt>

Rooms

在每个命名空间的内部,你可以随意定义一些频道(channel),我们可以把频道(channel)看作房间(room),socket们能够加入(join)或离开(leave)频道(房间)。

加入和离开频道(房间)

你可以调用 join 函数来让socket加入到频道(房间)中。

io.on('connection', function(socket) {
  socket.join('some room');  // 把默认命名空间中的socket加入到'some room'频道中
});

然后,当要服务器端要进行广播(broadcast)或者发射事件(emit)时,可以通过调用 to 或者 in (to和in是一样的)来指定某个频道(房间)。

// 服务器端给'some room'频道中的socket们发射'some event'事件
// 意思就是,这个'some event'事件只有'some room'频道中的socket们才能收到
io.to('some room').emit('some event');

如果想要离开频道,可以调用 leave函数来实现,方法和 join 一样。

io.on('connection', function(socket) { 
  // ...
  socket.leave('some room');   // 默认命名空间中的socket离开'some room'频道
});

默认房间

在Socket.IO中的每个socket都会被赋予一个随机的、独立的标识(id号) Socket#id。为了你的方便,每个socket一开始默认会自动地加入到一个房间中,而这个房间的“房间号”,就是socket的id号。

这样的话,会让广播消息(broadcast messages)给其他sockets变得简单。

io.on('connection', function(socket) {
  socket.on('say to someone', function(id, msg) {
    socket.broadcast.to(id).emit('my message', msg);  
  });
});

断开连接

在socket断开连接的时候,socket会自动离开(leave)所有频道,不需要我们来手动操作离开。

从外部的世界发送消息

在某些情况下,你可能想要把事件(event)从Socket.IO进程的上下文之外发送到Socket.IO的某个房间中的socket那里。

这里有一些办法可以解决上述问题,例如让你自己的频道(房间)发送消息到进程中。

为了实现“其他外部进程和Socket.IO进程相互通讯(发射事件)”,我们创建了2个模块:

通过使用这个Redis适配器(Adapter):

var io = require('socket.io')(3000);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));  // 使用adapter

你可以把消息(事件)从其他任何的进程发射(emit)到任何频道:

var io = require('socket.io-emitter')({ host: '127.0.0.1', port: 6379});  // 这里的io代表Redis数据库进程,不是Socket.IO进程
setInterval(function() {
  io.emit('time', new Date); // Redis数据库进程发射'time'消息(事件)
}, 5000);