本文收作者“大白菜”分享,有改动。注意:本系列是给IM初学者的文章,IM老油条们还望海涵,勿喷!

1、引言

这又是一篇基于Netty的IM编码实践文章,因为合成一篇内容太长,读起来太累,所以也就顺着作者的思路分开成4篇,读起来心理压力也就没那么大了。

这个系列的几篇文章分享的是:假设在没有任何成型的第3方IM库或SDK的情况下,以网络编程的基础技术视野,思考和实践如何基于Netty网络库从零写一个可以聊天的IM系统的过程,没有眼花缭乱的架构设计、也没有高端大气的模式设计方法论,有的只是从IM入门者的角度的思路和实战,适合IM初学者阅读。

本篇主要是徒手撸IM系列的开篇,主要讲解的是的IM设计思路,不涉及实践编码,希望给你带来帮助。

学习交流:

(本文已同步发布于:http://www.52im.net/thread-3963-1-1.html)

2、知识准备

* 重要提示:本系列文章主要是代码实战分享,如果你对即时通讯(IM)技术理论了解的不多,建议先详细阅读:《零基础IM开发入门:什么是IM系统?》、《新手入门一篇就够:从零开发移动端IM》。

不知道 Netty 是什么?这里简单介绍下:

Netty 是一个 Java 开源框架。Netty 提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

也就是说,Netty 是一个基于 NIO 的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。

Netty 相当简化和流线化了网络应用的编程开发过程,例如,TCP 和 UDP 的 Socket 服务开发。

Netty的基础入门好文章:

如果你连Java的NIO都不知道是什么,下面的文章建议优先读:

Netty源码和API的在线查阅地址:

3、系列文章

本文是系列文章的第1篇,以下是系列目录:

  1. 《基于Netty,徒手撸IM(一):IM系统设计篇》(* 本文)
  2. 《基于Netty,徒手撸IM(二):编码实践篇(单聊功能)》
  3. 《基于Netty,徒手撸IM(三):编码实践篇(群聊功能)》
  4. 《基于Netty,徒手撸IM(一):编码实践篇(系统优化)》

4、需求分析

业务场景: 本次实战就是模拟微信的IM聊天,每个客户端和服务端建立连接,并且可以实现点对点通信(单聊),点对多点通信(群聊)。

设计思路: 我们要实现的是点(客户端)对点(客户端)的通讯,但是我们大部分情况下接触的业务都是客户端和服务端之间的通讯(所谓的C/S模式?),客户端只需要知道服务端的 IP 地址和端口号即可发起通讯了。那么客户端和客户端应该怎么去设计呢?

技术思考:难道是手机和手机之间建立通讯连接(所谓的P2P),互相发送消息吗?

这种方案显然不是很好的方案:

  • 1)首先: 客户端和客户端之间通讯,首先需要确定对方的 IP 地址和端口号,显然不是很现实;
  • 2)其次: 即使有办法拿到对方的 IP 地址和端口号,那么每个点(客户端)既作为服务端还得作为客户端,无形之中增加了客户端的压力。

其实:我们可以使用服务端作为IM聊天消息的中转站,由服务端主动往指定客户端推送消息。如果是这种模式的话,那么 Http 协议是无法支持的(因为Http 是无状态的,只能一请求一响应的模式),于是就只能使用 TCP 协议去实现了。

Jack Jiang注:此处作者表述不太准确,因为虽然HTTP是无状态的,但一样可以实现即时通讯能力,有兴趣的读者可以阅读以下几篇文章,了解一下这些曾经利用HTTP实现即时通讯聊天的技术方法:

  1. 《新手入门贴:史上最全Web端即时通讯技术原理详解》
  2. 《Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE》
  3. 《网页端IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket》

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热门技术点,有兴趣的一定要读一读:

  1. 《移动端IM开发需要面对的技术问题》
  2. 《谈谈移动端 IM 开发中登录请求的优化》
  3. 《IM消息送达保证机制实现(一):保证在线实时消息的可靠投递》
  4. 《IM消息送达保证机制实现(二):保证离线消息的可靠投递》
  5. 《如何保证IM实时消息的“时序性”与“一致性”?》

6、IM群聊思路设计

群聊指的是一个组内多个用户之间的聊天,一个用户发到群组的消息会被组内任何一个成员接收 。

具体架构思路如下所示:

如上图所示,群聊通讯流程解析如下。

1)群聊其实和单聊整体上思路都是一致的,都是需要保存每个用户和通道的对应关系,方便后期通过用户 ID 去查找到对应的通道,再跟进通道推送消息。

2)如何把消息发送给多个组内的成员呢?

其实很简单,服务端再保存另外一份映射关系,那就是聊天室和成员的映射关系。发送消息时,首先根据聊天室 ID 找到对应的所有成员,然后再跟进各个成员的 ID 去查找到对应的通道,最后由每个通道进行消息的发送。

3)成员加入某个群聊组的时候,往映射表新增一条记录,如果成员退群的时候则删除对应的映射记录。

通过上面的架构图可以发现,群聊和单聊相比,其实就是多了一份映射关系而已。

其实群聊是IM里相对来说技术难度较高的功能,有兴趣的读者可以阅读下面这几篇:

  1. 《IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?》
  2. 《IM群聊消息如此复杂,如何保证不丢不重?》
  3. 《移动端IM中大规模群消息的推送如何保证效率、实时性?》
  4. 《现代IM系统中聊天消息的同步和存储方案探讨》
  5. 《关于IM即时通讯群聊消息的乱序问题讨论》
  6. 《IM群聊消息的已读回执功能该怎么实现?》
  7. 《IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?》
  8. 《一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践》

另外,对于超大规模群聊,技术难度更是指数上升:

  1. 《网易云信技术分享:IM中的万人群聊技术方案实践总结》
  2. 《阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处》
  3. 《IM群聊消息的已读未读功能在存储空间方面的实现思路探讨》
  4. 《企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等》
  5. 《融云IM技术分享:万人群聊消息投递方案的思考和实践》
  6. 《微信直播聊天室单房间1500万在线的消息架构演进之路》

7、本文小结

本篇主要是帮助读者掌握单聊和群聊的核心设计思路。

单聊: 主要是服务器保存了一份用户和通道之间的映射关系,发送消息的时候,根据接收人 ID 找到其对应的通道 Channel,Channel 的 write () 可以给客户端发送消息。

群聊: 保存两份关系,分别是用户 ID 和 Channel 之间的关系、群组 ID 和用户 ID 的关系。推送消息的时候,首先根据聊天组 ID 找到其对应的成员,遍历每个成员再进行找出其对应的通道即可。

整体来说,思路还是很简单的,掌握了该设计思路以后,你会发现设计一款 IM 聊天软件其实也不是很复杂。

8、相关文章

如果你觉得对本系列文章还不够详细,可以系统学习以下系列文章:

  1. 《跟着源码学IM(一):手把手教你用Netty实现心跳机制、断线重连机制》
  2. 《跟着源码学IM(二):自已开发IM很难?手把手教你撸一个Andriod版IM》
  3. 《跟着源码学IM(三):基于Netty,从零开发一个IM服务端》
  4. 《跟着源码学IM(四):拿起键盘就是干,教你徒手开发一套分布式IM系统》
  5. 《跟着源码学IM(五):正确理解IM长连接、心跳及重连机制,并动手实现》
  6. 《跟着源码学IM(六):手把手教你用Go快速搭建高性能、可扩展的IM系统》
  7. 《跟着源码学IM(七):手把手教你用WebSocket打造Web端IM聊天》
  8. 《跟着源码学IM(八):万字长文,手把手教你用Netty打造IM聊天》
  9. 《跟着源码学IM(九):基于Netty实现一套分布式IM系统》
  10. 《跟着源码学IM(十):基于Netty,搭建高性能IM集群(含技术思路+源码)》
  11. 《SpringBoot集成开源IM框架MobileIMSDK,实现即时通讯IM聊天功能》

9、参考资料

[1] 新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析

[2] 理论联系实际:一套典型的IM通信协议设计详解

[3] 浅谈IM系统的架构设计

[4] 简述移动端IM开发的那些坑:架构设计、通信协议和客户端

[5] 一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

[6] 一套原创分布式即时通讯(IM)系统理论架构方案

[7]  一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

[8] 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

[9] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

[10] 从新手到专家:如何设计一套亿级消息量的分布式IM系统

[11] 基于实践:一套百万消息量小规模IM系统技术要点总结

[12] 探探的IM长连接技术实践:技术选型、架构设计、性能优化

(本文已同步发布于:http://www.52im.net/thread-3963-1-1.html)

基于Netty,徒手撸IM(一):IM系统设计篇的更多相关文章

  1. 适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

    本文由“yuanrw”分享,博客:juejin.im/user/5cefab8451882510eb758606,收录时内容有改动和修订. 0.引言 站长提示:本文适合IM新手阅读,但最好有一定的网络 ...

  2. 基于netty轻量的高性能分布式RPC服务框架forest<上篇>

    工作几年,用过不不少RPC框架,也算是读过一些RPC源码.之前也撸过几次RPC框架,但是不断的被自己否定,最近终于又撸了一个,希望能够不断迭代出自己喜欢的样子. 顺便也记录一下撸RPC的过程,一来作为 ...

  3. 基于netty http协议栈的轻量级流程控制组件的实现

    今儿个是冬至,所谓“冬大过年”,公司也应景五点钟就放大伙儿回家吃饺子喝羊肉汤了,而我本着极高的职业素养依然坚持留在公司(实则因为没饺子吃没羊肉汤喝,只能呆公司吃食堂……).趁着这一个多小时的时间,想跟 ...

  4. 基于Netty打造RPC服务器设计经验谈

    自从在园子里,发表了两篇如何基于Netty构建RPC服务器的文章:谈谈如何使用Netty开发实现高性能的RPC服务器.Netty实现高性能RPC服务器优化篇之消息序列化 之后,收到了很多同行.园友们热 ...

  5. 基于netty轻量的高性能分布式RPC服务框架forest<下篇>

    基于netty轻量的高性能分布式RPC服务框架forest<上篇> 文章已经简单介绍了forest的快速入门,本文旨在介绍forest用户指南. 基本介绍 Forest是一套基于java开 ...

  6. 基于Netty的私有协议栈的开发

    基于Netty的私有协议栈的开发 书是人类进步的阶梯,每读一本书都使自己得以提升,以前看书都是看了就看了,当时感觉受益匪浅,时间一长就又还回到书本了!所以说,好记性不如烂笔头,以后每次看完一本书都写一 ...

  7. 基于netty的微服务架构

    基于netty的微服务架构 微服务一篇好文章 http://san-yun.iteye.com/blog/1693759 教程 http://udn.yyuap.com/doc/essential-n ...

  8. Android 基于Netty的消息推送方案之对象的传递(四)

    在上一篇文章中<Android 基于Netty的消息推送方案之字符串的接收和发送(三)>我们介绍了Netty的字符串传递,我们知道了Netty的消息传递都是基于流,通过ChannelBuf ...

  9. Android 基于Netty的消息推送方案之字符串的接收和发送(三)

    在上一篇文章中<Android 基于Netty的消息推送方案之概念和工作原理(二)> ,我们介绍过一些关于Netty的概念和工作原理的内容,今天我们先来介绍一个叫做ChannelBuffe ...

  10. Android 基于Netty的消息推送方案之概念和工作原理(二)

    上一篇文章中我讲述了关于消息推送的方案以及一个基于Netty实现的一个简单的Hello World,为了更好的理解Hello World中的代码,今天我来讲解一下关于Netty中一些概念和工作原理的内 ...

随机推荐

  1. NlogN 求最长不下降子序列(LIS)

    最长不下降子序列是一道非常经典的题目,我们假设题目如下: 有一个数组 $ a $,现在要从中抽取一个严格上升的子序列(子序列就是你可以从原序列里删除一些数,保留一部分数得到的新数列)(严格上升也就是不 ...

  2. 我开源了一个短视频应用(Go+React)|DouTok2.0 项目介绍

    前言 大家好,这里是白泽,拖更了一段时间,抱歉.在 DouTok2.0 可以初步允许大家接入开发之后,这篇文章才得以出炉. DouTok:一个开源的 web 端的短视频应用,采用微服务架构,包含前后端 ...

  3. OAS常见错误

    body { font-family: Arial, sans-serif; line-height: 1.6; margin: 20px } h1, h2 { color: rgba(51, 51, ...

  4. 无套路领取《AI应用开发专栏》

    最近有些时间没有更新技术文章了,都在忙着写<AI应用开发入门>专栏,专栏已整理放到了github上,有兴趣的小伙伴可以移步github阅读,地址见文末. 1.为什么写这个文档 之前陆续写了 ...

  5. 遗传算法+强化学习—TPG—Emergent Tangled Graph Representations for Atari Game Playing Agents_2

    最近在看进化算法在强化学习(RL)领域的一些应用,有些论文中将使用进化算法解决强化学习问题的算法归为非强化学习算法,然而又有些论文把使用进化算法解决强化学习问题的算法归为强化学习算法,不过更多的论文是 ...

  6. 进程相互作用之信号量PV操作及其代码实现

    目录 信号量PV操作 基本介绍 数据结构 解决进程互斥问题 解决进程同步问题 代码实现(以同步问题为例) 信号量PV操作 基本介绍 信号量(Semaphore):是表示资源的实体,是一个与队列有关的整 ...

  7. ETCD集群+ TLS认证

    目录 1.下载etcd cfssl相关命令 2.配置文件 /app/etcd/conf/conf.yml 3.用系统命令启动,创建 /usr/lib/systemd/system/etcd.servi ...

  8. 深入理解ReferenceQueue GC finalize Reference

    关于对象如何销毁以及finalize更详细的信息 目录 概述 1 先看一个对象finalize的顺序问题. 2 对象再生及finalize只能执行一次 3 SoftReference WeakRefe ...

  9. JDK 7 中的 Fork/Join 模式

    轻松实现多核时代的并行计算 随着多核时代的来临,软件开发人员不得不开始关注并行编程领域.而 JDK 7 中将会加入的 Fork/Join 模式是处理并行编程的一个经典的方法.虽然不能解决所有的问题,但 ...

  10. 基于golang的swagger

    Swagger 相关的工具集会根据 OpenAPI 规范去生成各式各类的与接口相关联的内容,常见的流程是编写注解 =>调用生成库->生成标准描述文件 =>生成/导入到对应的 Swag ...