跳到主要内容

WebSocket 实时服务

TSRPC 一开始便设计为 传输协议无关的架构,这使得它可以同时运行在 HTTP 和 WebSocket 上。 TSRPC 的二进制序列化特性,还能显著减小包体,帮助实时服务显著提升传输效能。

WebSocket API

TSRPC 本身的设计架构是传输协议无关的,这意味着我们之前实现的 HTTP API 也可以无缝运行在 WebSocket 协议之上。 只需要将 HttpServer 替换为 WsServer,将 HttpClient 替换为 WsClient 即可。例如:

import { WsServer } from 'tsrpc';

const server = new WsServer(serviceProto, {
port: 3000,
json: true
});
重要

由于 WebSocket 是长连接,所以使用前需要先 connect 连接,你可以通过 client.flows.postDisconnectFlow 来监听连接断开事件。

备注

WsWebSocket 的简写。

实时消息

在实时应用场景中,并非所有通讯都是 API 这样的 请求/响应 模型。 例如实时公告、聊天室等场景,客户端希望收到服务端的实时消息推送,而非发送请求轮询。

为此,TSRPC 提供了另一种基于 发布/订阅 的模型:消息服务 —— Message Service。

消息 Message 是 TSRPC 端到端通讯的最小单元。 我们可以使用 TypeScript 定义一种消息类型,它可以在服务端和客户端之间双向传递,也享有自动类型检测和二进制序列化特性。

定义消息

和 API 一样,1 种消息对应 1 个定义文件,存放在协议目录 backend/src/shared/protocols 下:

  • 消息文件命名为 Msg{消息名}.ts
  • 消息类型命名为 Msg{消息名},可以是 interfacetype
MsgChat.ts
export interface MsgChat {
name: string,
content: string
}

发送消息

消息可以双向传递,即可以从 Server 发给 Client,也可以从 Client 发给 Server。

Client 发送

client.sendMsg('Chat', {
name: 'k8w',
content: 'I love TSRPC.'
})

Server 发送

Server 同时可能连接着多个 Client,活跃中的所有连接都在 server.connections。 要给其中某个 Client 发送消息,可以使用 connection.sendMsg ,例如:

// 给第一个连接的 Client 发送消息
server.connections[0].sendMsg('Chat', {
name: 'System',
content: 'You are the first connection.'
})

Server 广播

要给所有 Client 发送消息,可以使用 server.broadcastMsg(),例如:

server.broadcastMsg('Chat', {
name: 'System',
content: 'This is a message to everyone.'
})

相比逐个连接去 sendMsg()broadcastMsg() 的好处在于,只执行一次序列化编码过程,减少 CPU 开销。

监听消息

监听 / 解除监听消息在 Server 和 Client 类似,例子如下:

// 监听(会返回传入的处理函数)
let handler = server.listenMsg('Chat', call=>{
server.broadcastMsg('Chat', call.msg);
});

// 取消监听
server.unlistenMsg('Chat', handler);

不同之处在于,由于 Server 同时可能连接着多个 Client,所以监听消息时收到的参数为 call: MsgCall。 其中除了消息内容( call.msg )外,还包含Client 连接( call.conn )等信息。

而 Client 由于只存在唯一的连接,故监听消息时,收到的参数即为消息本身:msg: MsgXXXX

例子:实时聊天室

使用 create-tsrpc-app 创建一个带浏览器前端的 WebSocket 项目,里面已经自带了一个极简的聊天室的例子,你也可以在这里查看:

https://github.com/k8w/tsrpc-examples/tree/main/examples/chatroom