Socket.io+Nest:服务端和客户端实现
本教程记录使用 NestJS 和 socket.io 创建一个实时计数器模块,并提供客户端代码。用以备忘。
环境设置
-
npm
-
NestJS CLI
使用 NestJS CLI 创建一个新项目:
1npm i -g @nestjs/cli
2nest new realtime-counter
3cd realtime-counter
创建实时计数器模块
接下来,在 NestJS 项目中创建一个名为 CounterModule
的实时计数器模块,并使用 socket.io 实现。
安装依赖
在 realtime-counter
项目根目录下,安装所需的依赖:
1npm install @nestjs/platform-socket.io socket.io socket.io-client
编写代码
创建 CounterModule
在 src
目录下,创建一个名为 counter.module.ts
的新文件,并写入以下代码:
1// src/counter.module.ts
2import { Module } from '@nestjs/common';
3import { SocketIoModule } from '@nestjs/platform-socket.io';
4import { CounterGateway } from './counter.gateway';
5
6@Module({
7 imports: [SocketIoModule.forRoot({})],
8 providers: [CounterGateway],
9})
10export class CounterModule {}
这里,我们使用 @nestjs/platform-socket.io
和 @nestjs/websockets
包创建了一个 WebSocket 网关,即 CounterGateway
。我们还将 CounterGateway
添加到 providers
数组中,以使它成为 NestJS 中的可注入对象。
创建 CounterGateway
同目录下,创建一个名为 counter.gateway.ts
的新文件,并写入以下代码:
1// src/counter.gateway.ts
2import {
3 SubscribeMessage,
4 WebSocketGateway,
5 WebSocketServer,
6 OnGatewayConnection,
7} from '@nestjs/websockets';
8import { Server, Socket } from 'socket.io';
9
10@WebSocketGateway()
11export class CounterGateway implements OnGatewayConnection {
12 @WebSocketServer()
13 server: Server;
14
15 async handleConnection(client: Socket) {
16 let count = 0;
17 const interval = setInterval(() => {
18 count++;
19 client.emit('count', count);
20
21 if (count >= 25) {
22 clearInterval(interval);
23 client.disconnect(true);
24 }
25 }, 1000);
26 }
27
28 @SubscribeMessage('start')
29 handleMessage(client: Socket) {
30 client.emit('count', 0);
31 }
32}
这里,我们使用 @nestjs/websockets
包创建了一个 WebSocket 网关类 CounterGateway
,它实现了 OnGatewayConnection
接口,用于处理客户端连接事件。
在 handleConnection
方法中,我们使用 setInterval
创建了一个计时器,它将每秒钟将 count
变量递增 1,并将 count
的值通过 client.emit
方法发送给客户端。在 count
达到 25 时,我们使用 clearInterval
方法停止计时器,并通过 client.disconnect(true)
方法断开客户端连接。
在 handleMessage
方法中,我们监听客户端的 start
事件,并通过 client.emit('count', 0)
方法向客户端发送一个初始值为 0 的 count
。
现在,我们已经完成了服务器端的代码。接下来,创建一个客户端来测试它。
创建客户端
在项目根目录下,创建一个名为 client.js
的文件,并写入以下代码:
1// client.js
2const io = require('socket.io-client');
3const socket = io('http://localhost:3000');
4
5socket.on('connect', () => {
6 console.log('Connected to the server');
7 socket.emit('start');
8});
9
10socket.on('count', (count) => {
11 console.log('Current count:', count);
12});
13
14socket.on('disconnect', () => {
15 console.log('Disconnected from the server');
16 process.exit(0);
17});
这里,我们使用 socket.io-client
包创建了一个 WebSocket 客户端。在客户端连接到服务器时,我们通过 socket.emit('start')
向服务器发送一个 start
事件,以便服务器开始计数。
当服务器发送一个 count
事件时,我们通过 socket.on('count', (count) => {...})
监听它,并将 count
的值打印到控制台上。
当客户端断开连接时,我们通过 socket.on('disconnect', () => {...})
监听它,并输出一条相关的消息。
现在,我们已经完成了客户端的代码。接下来,启动服务器并运行客户端,以测试我们的实时计数器。
测试实时计数器
在 realtime-counter
项目根目录下,运行以下命令以启动 NestJS 服务器:
1npm run start
然后,在一个新的终端中,运行以下命令以运行客户端:
1node client.js
如果一切正常,你应该能够在客户端控制台上看到实时计数器输出。计数器将从 0 开始,每秒钟递增 1,直到计数器达到 25,然后客户端将断开连接。
添加错误处理逻辑
最后,我们可以在客户端代码中添加一些错误处理逻辑。以下是修改后的 client.js
文件,添加了处理连接错误和重连尝试的代码:
1// client.js
2const io = require('socket.io-client');
3const socket = io('http://localhost:3000', {
4 reconnectionAttempts: 5,
5 timeout: 5000,
6});
7
8socket.on('connect', () => {
9 console.log('Connected to the server');
10 socket.emit('start');
11});
12
13socket.on('count', (count) => {
14 console.log('Current count:', count);
15});
16
17socket.on('connect_error', (error) => {
18 console.error('Connection error:', error.message);
19
20});
21
22socket.on('reconnecting', (attemptNumber) => {
23 console.log(`Attempting to reconnect (${attemptNumber})...`);
24});
25
26socket.on('reconnect_failed', () => {
27 console.error('Failed to reconnect. Exiting...');
28 process.exit(1);
29});
30
31socket.on('disconnect', () => {
32 console.log('Disconnected from the server');
33 process.exit(0);
34});
这里,我们在 io
构造函数的第二个参数中设置了 reconnectionAttempts
和 timeout
参数,用于指定客户端重连尝试的次数和超时时间。
当客户端无法连接到服务器或连接中断时,在客户端控制台上显示相关错误信息。同时,客户端将尝试重新连接服务器,最多尝试 5 次。如果所有重连尝试都失败,客户端将输出错误信息并退出。
现在,我们已经完成了实时计数器的 NestJS 模块和客户端代码。
本文由 GPT4 编写。