基于 Netty,徒手撸 IM(一):IM 系统设计篇
本文收作者“大白菜”分享,有改动。注意:本系列是给 IM 初学者的文章,IM 老油条们还望海涵,勿喷!
1、引言
这又是一篇基于 Netty 的 IM 编码实践文章,因为合成一篇内容太长,读起来太累,所以也就顺着作者的思路分开成 4 篇,读起来心理压力也就没那么大了。
这个系列的几篇文章分享的是:假设在没有任何成型的第 3 方 IM 库或 SDK 的情况下,以网络编程的基础技术视野,思考和实践如何基于 Netty 网络库从零写一个可以聊天的 IM 系统的过程,没有眼花缭乱的架构设计、也没有高端大气的模式设计方法论,有的只是从 IM 入门者的角度的思路和实战,适合 IM 初学者阅读。
本篇主要是徒手撸 IM 系列的开篇,主要讲解的是的 IM 设计思路,不涉及实践编码,希望给你带来帮助。
2、知识准备
* 重要提示:本系列文章主要是代码实战分享,如果你对即时通讯(IM)技术理论了解的不多,建议先详细阅读:《零基础IM开发入门:什么是IM系统?》、《新手入门一篇就够:从零开发移动端IM》。
不知道 Netty 是什么?这里简单介绍下:
Netty 是一个 Java 开源框架。Netty 提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
也就是说,Netty 是一个基于 NIO 的客户、服务器端编程框架,使用 Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。
Netty 相当简化和流线化了网络应用的编程开发过程,例如,TCP 和 UDP 的 Socket 服务开发。
Netty 的基础入门好文章:
3、系列文章
本文是系列文章的第 1 篇,以下是系列目录:
《基于Netty,徒手撸IM(一):IM系统设计篇》(* 本文)
《基于 Netty,徒手撸 IM(二):编码实践篇(单聊功能)》
《基于 Netty,徒手撸 IM(三):编码实践篇(群聊功能)》
《基于 Netty,徒手撸 IM(一):编码实践篇(系统优化)》
4、需求分析
业务场景: 本次实战就是模拟微信的 IM 聊天,每个客户端和服务端建立连接,并且可以实现点对点通信(单聊),点对多点通信(群聊)。
设计思路: 我们要实现的是点(客户端)对点(客户端)的通讯,但是我们大部分情况下接触的业务都是客户端和服务端之间的通讯(所谓的 C/S 模式?),客户端只需要知道服务端的 IP 地址和端口号即可发起通讯了。那么客户端和客户端应该怎么去设计呢?
技术思考:难道是手机和手机之间建立通讯连接(所谓的 P2P),互相发送消息吗?
这种方案显然不是很好的方案:
1)首先: 客户端和客户端之间通讯,首先需要确定对方的 IP 地址和端口号,显然不是很现实;
2)其次: 即使有办法拿到对方的 IP 地址和端口号,那么每个点(客户端)既作为服务端还得作为客户端,无形之中增加了客户端的压力。
其实:我们可以使用服务端作为 IM 聊天消息的中转站,由服务端主动往指定客户端推送消息。如果是这种模式的话,那么 Http 协议是无法支持的(因为 Http 是无状态的,只能一请求一响应的模式),于是就只能使用 TCP 协议去实现了。
Jack Jiang 注:此处作者表述不太准确,因为虽然 HTTP 是无状态的,但一样可以实现即时通讯能力,有兴趣的读者可以阅读以下几篇文章,了解一下这些曾经利用 HTTP 实现即时通讯聊天的技术方法:
5、IM 单聊思路设计
5.1 通讯架构原理
以下是通讯架构原理图:
如上图所示,通讯流程解析如下:
1)实现客户端和客户端之间通讯,那么需要使用服务端作为通讯的中转站,每个客户端都必须和服务端建立连接;
2)每个客户端和服务端建立连接之后,服务端保存用户 ID 和通道的映射关系,其中用户 ID 作为客户端的唯一标识;
3)客户端 A 往客户端 B 发送消息时,先把消息发送到服务端,再有服务端往客户端 B 进行推送。
针对上述第“3)”点,服务端如何找到客户端 B 呢?
客户端 A 往服务端发送消息时,消息携带的信息有:“客户端 A 用户 ID”、“客户端 B 用户 ID”、“消息内容”。这样服务端就能顺利找到服务端 B 的通道并且进行推送消息了。
5.2 消息推送流程
每个客户端和服务端建立连接的时候,必须把个人用户信息上传到服务端,由服务端统一保存映射关系。如果某个客户端下线了,则服务端监听到连接断开,删除对应的映射关系。
其次:发起群聊的时候,需要传递 touser 字段,服务端根据该字段在映射表里面查找到对应的连接通道并发起消息推送。
上述逻辑原理如下图所示:
5.3 更多的细节
其实在真正要做 IM 之前,要考虑的技术细节还是很多的,以下这几篇文章就步及到了典型的几个 IM 热门技术点,有兴趣的一定要读一读:
6、IM 群聊思路设计
群聊指的是一个组内多个用户之间的聊天,一个用户发到群组的消息会被组内任何一个成员接收 。
具体架构思路如下所示:
如上图所示,群聊通讯流程解析如下。
1)群聊其实和单聊整体上思路都是一致的,都是需要保存每个用户和通道的对应关系,方便后期通过用户 ID 去查找到对应的通道,再跟进通道推送消息。
2)如何把消息发送给多个组内的成员呢?
其实很简单,服务端再保存另外一份映射关系,那就是聊天室和成员的映射关系。发送消息时,首先根据聊天室 ID 找到对应的所有成员,然后再跟进各个成员的 ID 去查找到对应的通道,最后由每个通道进行消息的发送。
3)成员加入某个群聊组的时候,往映射表新增一条记录,如果成员退群的时候则删除对应的映射记录。
通过上面的架构图可以发现,群聊和单聊相比,其实就是多了一份映射关系而已。
其实群聊是 IM 里相对来说技术难度较高的功能,有兴趣的读者可以阅读下面这几篇:
7、本文小结
本篇主要是帮助读者掌握单聊和群聊的核心设计思路。
单聊: 主要是服务器保存了一份用户和通道之间的映射关系,发送消息的时候,根据接收人 ID 找到其对应的通道 Channel,Channel 的 write () 可以给客户端发送消息。
群聊: 保存两份关系,分别是用户 ID 和 Channel 之间的关系、群组 ID 和用户 ID 的关系。推送消息的时候,首先根据聊天组 ID 找到其对应的成员,遍历每个成员再进行找出其对应的通道即可。
整体来说,思路还是很简单的,掌握了该设计思路以后,你会发现设计一款 IM 聊天软件其实也不是很复杂。
8、相关文章
如果你觉得对本系列文章还不够详细,可以系统学习以下系列文章:
9、参考资料
[1] 新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析
[3] 浅谈IM系统的架构设计
[4] 简述移动端IM开发的那些坑:架构设计、通信协议和客户端
[5] 一套海量在线用户的移动端IM架构设计实践分享(含详细图文)
[7] 一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践
[8] 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等
[9] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
[10] 从新手到专家:如何设计一套亿级消息量的分布式IM系统
[11] 基于实践:一套百万消息量小规模IM系统技术要点总结
[12] 探探的IM长连接技术实践:技术选型、架构设计、性能优化
学习交流:
- 移动端 IM 开发入门文章:《新手入门一篇就够:从零开发移动端IM》
- 开源 IM 框架源码:https://github.com/JackJiang2011/MobileIMSDK(备用地址点此)
(本文已同步发布于:http://www.52im.net/thread-3963-1-1.html)
评论