在开始打造我们自己的实时聊天系统之前,我们需要先思考????几个问题:

  • 用户体量大概多少?如何扩容?
  • 用户分布的区域?
  • 如何保证消息(低延时、必)送达?

做过 IM 或信令的小伙伴都知道,实时传输对服务端有着颇高的要求。就以社交 APP 为例,每秒种要处理成百上千甚至更多的文字和图片的传输;弱网丢包的情况要保证消息的完整性的同时还要确保消息已送达;这其中的技术原理和解决方案不是一个 WebSocket 所能涵盖的。

就消息必达而言,系统除了要有择优链路能力以外,还要具备多活链路。比如:一旦有一条链路出现问题,那么该消息就不一定能够送达。然而现实环境往往必我们想象中理想环境来的更糟糕和残酷,与此同时我们还要面对:网络丢包用户量指数上升并发上不去甚至系统宕机等等。

因此,要打造一个怎样的聊天系统,取决于我们产品的需求,根据需要选择集群部署的数量、节点的分布等诸多因素。

实时聊天系统应具备的特性

  • 高并发
  • 低延时
  • 消息必达
  • 弱网抗性
  • 集群部署
  • 消息推送(可选)

实时聊天系统应具备的功能

  • 点对点消息
  • 群组消息
  • 呼叫邀请

现在的社交 APP 玩法十分丰富,提供图文传输还加入了实时通讯模块,衍生出了直播连麦、主播 PK等诸多玩法,其中很大一部分都是通过自定义实时消息来完成。举个简单的例子:微信电话,A 给 B 发送一条带状态的消息、B 接收或者挂断操作之后,状态会被锁定之后无法变更,系统再将结果发送给 A,这个过程我们称之为呼叫邀请。

总之,实时消息不仅能带来通讯便利,同时还能辅助我们丰富我们的业务流程。

Vue3 + Tailwind + RTM = 实时聊天系统

web技术分享| 一人一天一个可移植的实时聊天系统_webRTC

项目说明

本项目 0 业务代码,因此只能通过指定几个固定的频道房间,来演示群组消息,大家如果有需要可以对接自己的业务系统替换项目中的随机头像、随机昵称、个性签名等数据;完善点对点消息呼叫邀请等功能;同时还可以通过 RTM 的自定义消息进行广播处理更多复杂的情形。

源码

源码请查看

使用 Vite 构建 Vue3 项目

使用 Vite 构建一个 Vue3 项目,详情参考官方文档
创建项目

# npm 6.x
npm init @vitejs/app my-chat-app --template vue

# npm 7+, 需要额外的双横线:
npm init @vitejs/app my-chat-app -- --template vue

# yarn
yarn create @vitejs/app my-chat-app --template vue

安装依赖

cd my-chat-app

npm install
npm run dev

TailWind + TailWindComponents = UI

为什么我们要选择 tailwindcss
tailwindcss 不仅节省了编写 css 的时间,还避免了命名烦恼,同时tailwindComponents 提供了很多免费(使用 tailwind 开发)的 UI 组件,我们可以从中找到一些现成的 UI 组件,何乐而不为呢?比如:下面是我们从tailwindComponents 查找到的一些 chat 相关的组件。

web技术分享| 一人一天一个可移植的实时聊天系统_前端技术_02

安装 tailwindcss

npm install -D tailwindcss@latest postcss@latest autoprefixer@latest

自动生成 tailwind 的配置文件

npx tailwindcss init -p

配置 tailwindcss
这里就不做代码的搬运工了,详情请参考官方文档 ,中文请参考中文文档

集成 RTM 模块

项目使用的 RTM SDK,相关 API 请查看官方文档,大家可以根据需求替换。

安装 RTM

npm install ar-rtm-sdk -D

导入 RTM SDK

import ArRTM from "ar-rtm-sdk"

创建客户端

const rtmClient = ArRTM.createInstance(Config.RTM_APP_ID, {
	// 设置日志级别
	logFilter: ArRTM.LOG_FILTER_OFF
});

登录 RTM 系统

// 随机用户 ID,可以对接自己业务系统中的 UID
const randomUserId = '' + Math.ceil(Math.random() * Math.pow(10, 10));
const uid = await rtmClient.login({
	uid: randomUserId
});

加入群组&监听群组消息回调

// 创建群组
const rtmChannel = rtmClient.createChannel(group.groupId);
// 加入群组
await rtmChannel.join();
// 监听群组消息
rtmChannel.on("ChannelMessage", (message, peerId, messagePros) => {
	if (message.text) {
		// 解析消息内容
		const msgObj = JSON.parse(message.text);
		// TODO...(例如,将消息显示到页面上)
	}
});

根据业务拓展

  • 点对点消息
    当对接业务系统后,可以使用业务中的 UID 作为 RTM 的 UID 登录,可以根据 UID 定向发送点对点消息。
  • 实时音视频通话
    当对接业务系统后,可以向指定 UID 的用户发起呼叫邀请,在对方接收之后,双方加入同一个音视频通讯的房间,前提是项目需要集成音视频通讯的模块。

web技术分享| 一人一天一个可移植的实时聊天系统_实时聊天_03