API 概述
¥Overview of the API
在继续之前,让我们快速浏览一下 Socket.IO 提供的 API:
¥Before we go any further, let's take a quick tour of the API provided by Socket.IO:
通用 API
¥Common API
以下方法对于客户端和服务器均可用。
¥The following methods are available for both the client and the server.
基本触发
¥Basic emit
正如我们在 步骤 #4 中看到的,你可以使用 socket.emit()
向对方发送任何数据:
¥As we have seen in step #4, you can send any data to the other side with socket.emit()
:
- From client to server
- From server to client
客户端
¥Client
socket.emit('hello', 'world');
服务器
¥Server
io.on('connection', (socket) => {
socket.on('hello', (arg) => {
console.log(arg); // 'world'
});
});
服务器
¥Server
io.on('connection', (socket) => {
socket.emit('hello', 'world');
});
客户端
¥Client
socket.on('hello', (arg) => {
console.log(arg); // 'world'
});
你可以发送任意数量的参数,并且支持所有可序列化的数据结构,包括二进制对象,如 ArrayBuffer、TypedArray 或 缓冲(仅限 Node.js):
¥You can send any number of arguments, and all serializable data structures are supported, including binary objects like ArrayBuffer, TypedArray or Buffer (Node.js only):
- From client to server
- From server to client
客户端
¥Client
socket.emit('hello', 1, '2', { 3: '4', 5: Uint8Array.from([6]) });
服务器
¥Server
io.on('connection', (socket) => {
socket.on('hello', (arg1, arg2, arg3) => {
console.log(arg1); // 1
console.log(arg2); // '2'
console.log(arg3); // { 3: '4', 5: <Buffer 06> }
});
});
服务器
¥Server
io.on('connection', (socket) => {
socket.emit('hello', 1, '2', { 3: '4', 5: Buffer.from([6]) });
});
客户端
¥Client
socket.on('hello', (arg1, arg2, arg3) => {
console.log(arg1); // 1
console.log(arg2); // '2'
console.log(arg3); // { 3: '4', 5: ArrayBuffer (1) [ 6 ] }
});
不需要在对象上调用 JSON.stringify()
:
¥Calling JSON.stringify()
on objects is not needed:
// BAD
socket.emit('hello', JSON.stringify({ name: 'John' }));
// GOOD
socket.emit('hello', { name: 'John' });
回执
¥Acknowledgements
事件很棒,但在某些情况下你可能需要更经典的请求-响应 API。在 Socket.IO 中,该功能被命名为 "acknowledgements"。
¥Events are great, but in some cases you may want a more classic request-response API. In Socket.IO, this feature is named "acknowledgements".
它有两种口味:
¥It comes in two flavors:
使用回调函数
¥With a callback function
你可以添加一个回调作为 emit()
的最后一个参数,一旦对方确认了该事件,就会调用该回调:
¥You can add a callback as the last argument of the emit()
, and this callback will be called once the other side has acknowledged the event:
- From client to server
- From server to client
客户端
¥Client
socket.timeout(5000).emit('request', { foo: 'bar' }, 'baz', (err, response) => {
if (err) {
// the server did not acknowledge the event in the given delay
} else {
console.log(response.status); // 'ok'
}
});
服务器
¥Server
io.on('connection', (socket) => {
socket.on('request', (arg1, arg2, callback) => {
console.log(arg1); // { foo: 'bar' }
console.log(arg2); // 'baz'
callback({
status: 'ok'
});
});
});
服务器
¥Server
io.on('connection', (socket) => {
socket.timeout(5000).emit('request', { foo: 'bar' }, 'baz', (err, response) => {
if (err) {
// the client did not acknowledge the event in the given delay
} else {
console.log(response.status); // 'ok'
}
});
});
客户端
¥Client
socket.on('request', (arg1, arg2, callback) => {
console.log(arg1); // { foo: 'bar' }
console.log(arg2); // 'baz'
callback({
status: 'ok'
});
});
使用 Promise
¥With a Promise
emitWithAck()
方法提供相同的功能,但返回一个 Promise,一旦对方确认事件,该 Promise 就会解析:
¥The emitWithAck()
method provides the same functionality, but returns a Promise which will resolve once the other side acknowledges the event:
- From client to server
- From server to client
客户端
¥Client
try {
const response = await socket.timeout(5000).emitWithAck('request', { foo: 'bar' }, 'baz');
console.log(response.status); // 'ok'
} catch (e) {
// the server did not acknowledge the event in the given delay
}
服务器
¥Server
io.on('connection', (socket) => {
socket.on('request', (arg1, arg2, callback) => {
console.log(arg1); // { foo: 'bar' }
console.log(arg2); // 'baz'
callback({
status: 'ok'
});
});
});
服务器
¥Server
io.on('connection', async (socket) => {
try {
const response = await socket.timeout(5000).emitWithAck('request', { foo: 'bar' }, 'baz');
console.log(response.status); // 'ok'
} catch (e) {
// the client did not acknowledge the event in the given delay
}
});
客户端
¥Client
socket.on('request', (arg1, arg2, callback) => {
console.log(arg1); // { foo: 'bar' }
console.log(arg2); // 'baz'
callback({
status: 'ok'
});
});
不支持 Promise 的环境(例如 Internet Explorer)需要添加一个 polyfill 或使用像 babel 这样的编译器才能使用此功能(但这超出了本教程的范围)。
¥Environments that do not support Promises (such as Internet Explorer) will need to add a polyfill or use a compiler like babel in order to use this feature (but this is out of the scope of this tutorial).
捕获所有监听器
¥Catch-all listeners
包罗万象的监听器是为任何传入事件调用的监听器。这对于调试你的应用很有用:
¥A catch-all listeners is a listener that will be called for any incoming event. This is useful for debugging your application:
发送者
¥Sender
socket.emit('hello', 1, '2', { 3: '4', 5: Uint8Array.from([6]) });
接收者
¥Receiver
socket.onAny((eventName, ...args) => {
console.log(eventName); // 'hello'
console.log(args); // [ 1, '2', { 3: '4', 5: ArrayBuffer (1) [ 6 ] } ]
});
同样,对于传出数据包:
¥Similarly, for outgoing packets:
socket.onAnyOutgoing((eventName, ...args) => {
console.log(eventName); // 'hello'
console.log(args); // [ 1, '2', { 3: '4', 5: ArrayBuffer (1) [ 6 ] } ]
});
服务器 API
¥Server API
广播
¥Broadcasting
正如我们在 步骤 #5 中看到的,你可以使用 io.emit()
将事件广播到所有连接的客户端:
¥As we have seen in step #5, you can broadcast an event to all connected clients with io.emit()
:
io.emit('hello', 'world');
房间
¥Rooms
在 Socket.IO 术语中,房间是套接字可以加入和离开的任意通道。它可用于向连接的客户端子集广播事件:
¥In Socket.IO jargon, a room is an arbitrary channel that sockets can join and leave. It can be used to broadcast events to a subset of connected clients:
io.on('connection', (socket) => {
// join the room named 'some room'
socket.join('some room');
// broadcast to all connected clients in the room
io.to('some room').emit('hello', 'world');
// broadcast to all connected clients except those in the room
io.except('some room').emit('hello', 'world');
// leave the room
socket.leave('some room');
});
基本上就是这样!为了便于将来参考,整个 API 可以在 此处(服务器)和 此处(客户端)中找到。
¥That's basically it! For future reference, the whole API can be found here (server) and here (client).