SocketIO
Socket.io 是一个业界常用库,可用于在浏览器和服务器之间进行实时,双向和基于事件的通信。

Midway 提供了对 Socket.io 的支持和封装,能够简单的创建一个 Socket.io 服务。本篇内容演示了如何在 Midway 体系下,提供 Socket.io 服务的方法。
Midway 当前采用了最新的 Socket.io (v4.0.0) 进行开发。
相关信息:
提供服务
| 描述 | |
|---|---|
| 可用于标准项目 | ✅ |
| 可用于 Serverless | ❌ |
| 可用于一体化 | ✅ |
| 包含独立主框架 | ✅ |
| 包含独立日志 | ❌ |
安装依赖
在现有项目中安装 Socket.io 的依赖。
$ npm i @midwayjs/socketio@4 --save
## 客户端可选
$ npm i @types/socket.io-client socket.io-client --save-dev
或者在 package.json 中增加如下依赖后, 重新安装。
{
"dependencies": {
"@midwayjs/socket.io": "^4.0.0",
// 客户端可选
"socket.io-client": "^4.4.1",
// ...
},
"devDependencies": {
// 客户端可选
"@types/socket.io-client": "^1.4.36",
// ...
}
}
开启组件
@midwayjs/socket.io 可以作为独立主框架使用。
import { Configuration } from '@midwayjs/core';
import * as socketio from '@midwayjs/socketio';
@Configuration({
imports: [socketio],
// ...
})
export class MainConfiguration {
async onReady() {
// ...
}
}
也可以附加在其他的主框架下,比如 @midwayjs/koa 。
import { Configuration } from '@midwayjs/core';
import * as koa from '@midwayjs/koa';
import * as socketio from '@midwayjs/socketio';
@Configuration({
imports: [koa, socketio],
// ...
})
export class MainConfiguration {
async onReady() {
// ...
}
}
目录结构
下面是 Socket.io 项目的基础目录结构,和传统应用类似,我们创建了 socket 目录,用户存放 Soscket.io 业务的服务代码。
.
├── package.json
├── src
│ ├── configuration.ts ## 入口配置文件
│ ├── interface.ts
│ └── socket ## socket.io 服务的文件
│ └── hello.controller.ts
├── test
├── bootstrap.js ## 服务启动入口
└── tsconfig.json
Socket.io 工作原理
Socket.io 服务器和 Socket.io 客户端(浏览器,Node.js 或另一种编程语言)之间的双向通道通过 WebSocket连接 建立起来,在不可用时,将使用 HTTP 长轮询作为备用手段。
Socket.io 代码是基于 Engine.io 库搭建起来的,是属于 Engine.io 的上层实现。Engine.io 负责整个服务端和客户端连接的部分,包括连接检查,传输方式等等。而 Socket.io 负责上层的重连,封包缓冲,广播等等特性。
Socket.io(Engine.io)实现了两种 Transports(传输方式)。
第一种是 HTTP 长轮询。HTTP Get 请求用于 long-running(长连接),Post 请求用于 short-running(短连接)。

第二种是 WebSocket 协议,直接基于 WebSocket Connection 实现。它在服务器和客户端 之间提供了双向且低延迟的通信通道。
在默认的情况下,Socket.io 会先采用 HTTP 长轮询进行连接,并发送一个类似下面结构的数据。
{
"sid": "FSDjX-WRwSA4zTZMALqx", // 连接的 session id
"upgrades": ["websocket"], // 可升级的协议
"pingInterval": 25000, // 心跳时间间隔
"pingTimeout": 20000 // 心跳超时时间
}
当当前的服务满足升级到 WebSocket 协议的要求时,会自动升级到 WebSocket 协议,如下图。

- 1、第一次握手,传输 sid 等结构
- 2、使用 HTTP 长轮询发送数据
- 3、使用 HTTP 长轮询返回数据
- 4、升级协议,使用 WebSocket 协议发送数据
- 5、当协议升级后,关闭之前的长轮询
之后就开始正常的 WebSocket 通信了。