在信息高度发达的今天,IM基本上已经成为了一个社交应用的标配。本文将以一个移动开发者的视角,探讨移动端即时通信系统的技术选型和关键要点。html
1 即时通信系统的需求java
任何技术系统都来源于真实业务的需求,作架构设计以前应该先设定好目标。做为一个即时通信应用,能够参考微信的使用体验,你须要保证如下特性:数据库
1,实时。消息的接收端应该可以及时收到并处理消息。缓存
2,不丢。须要保证全部的消息都顺利送达。安全
3,不重。重复的消息对用户来讲是一种糟糕的体验。性能优化
4,保序。只要顺序一乱,消息根本没发看。服务器
5,节能。流量难得,电量难得,能省则省。微信
6,安全。若是涉及敏感数据,安全必须重视。网络
7,流畅。卡顿的应用是不会被用户接受的。架构
2 关键技术点
为了保证消息的实时性,有两种思路:
1,长轮询方式,高频率地从服务端拉取新消息。这种方式其实就是传统的请求-响应模型,如今不少体育文字直播软件也采起这种方式。这种方法虽然简单,但有不少缺点。一是会产生不少请求,这对服务器的压力和用户的流量都是浪费。二是消息仍然不够及时,不考虑传输时间,最长的延迟就是轮询的间隔。
2,消息的生产者主动推送消息。这应该是更好的选择,能够解决长轮询的缺点。咱们的即时通信系统也会采用这种方式。使用长链接,并且链接必须是稳定可靠的,才能确保消息的实时性。
2.1 数据通讯协议
服务端与客户端之间须要协商好数据格式,这是数据传输和数据处理的基础。协议的设计须要着重考虑第一节提到几点需求。
XMPP和MQTT是当前比较成熟的两种消息协议。若是能较好地处理你的业务需求,就没有必要重复造轮子。有不少企业的业务有特殊需求,能够考虑根据实际状况自定义协议,从头开始显然是不现实的,能够参考已经成熟的协议再作设计和开发。具体协议内容在此不详细展开,只作优劣的比较。
2.1.1 XMPP
XMPP是一种以XML为基础的开放式即时通信协议。
XMPP的优势是安全,SASL及TL等技术的可靠安全性已内置于核心XMPP技术规格中。
XMPP 协议的最主要的一点就是开放,不论是协议、客户端,仍是 Server 端,都有成熟的实现方案。
基于XML,它天生拥有很强的灵活性,能够在核心协议之上方便地进行定制化。Google Talk就是采用这种协议。
可是XMPP的缺点也很明显。首先,XMPP协议的方式被编码为一个单一的长的XML文件,所以没法提供修改二进制数据。其次,XML 有大量的标签冗余信息,网络流量的 70% 都消耗在 XMPP 协议层了,这在移动互联网时代,流量和电量是一个不可忽视的消耗。
2.1.2 MQTT
MQTT协议是由IBM提出的基于发布/订阅模型的消息传输协议,相比于XMPP,它显得很是轻量小巧,协议内容包括固定头部+可变头部+消息体,最下的状况下头部只须要两个字节,在传输开销上有着巨大的优点,能够节省流量和电量。
MQTT能够保证消息的可靠性,它包括三种不一样的服务质量(最多只传一次、最少被传一次、一次且只传一次),若是客户端意外掉线,可使用“遗愿”发布一条消息,同时支持持久订阅。
XMPP使用XML,是一个历史的选择,在如今移动应用的场景下,我的更加推荐MQTT。据了解,很多企业,包括作IM SDK的厂商,也是在MQTT的基础上进行自定义的扩展和修改。
2.2 链接的稳定性
移动互联网的场景下,网络环境常常变化,须要保证链接是稳定的。
2.2.1 心跳
最经典的作法就是使用心跳,实时地检测链接状态。一般是客户端每隔一小段时间向服务器发送一个数据包,通知服务器本身仍然在线,并传输一些可能必要的数据。若是在必定时间内服务器没有响应,则认为链接可能已经断开,从新尝试链接。
伪代码以下:
上述代码的心跳间隔是固定的。因为心跳包也是会消耗流量的,所以应该找到一个理想的心跳周期,在能敏锐地察觉链接变化的前提下,尽可能大地增长周期间隔。所以能够作一个优化,是使心跳间隔动态增长。
2.2.2 多链接尝试
(1)多链接尝试
考虑到不一样地区不一样网络运营商的状况下,用户可能由于网络限制,链接不上咱们的服务或者比较慢。咱们在实践中就发现,某些网络运营商将某些端口封禁了,致使部分用户链接不上服务。为了解决这个问题,能够提供多个ip和多个端口,客户端在链接某个ip比较慢的状况下,能够进行轮询,切换到一个更快的ip。
(2)长链接与短链接结合
这只是一条退路,而不是常规武器。
在长链接实在链接不上的状况下,能够考虑作降级,使用短链接长轮询的方式进行替代。
2.3 服务质量
系统的设计每每存在着取舍和妥协。正如TCP比UDP更加可靠,但它的负载会更高。
在即时通信系统中也存在着取舍的问题,是追求极速送达,仍是在传输上作可靠性的保证,确保不丢不重?不一样的业务类型可能须要不一样的服务质量,MQTT协议提供了三种服务质量,能够做为参考:
QoS 0: 至多发送一次,发送即丢弃。没有确认消息,也不知道对方是否收到。针对的消息不重要,丢失也无所谓。
QoS 1: 至少发送一次。发送以后,会等待接收方ack确认。在必定时间以内,若是没有收到ack,则会再发一次,一直到接收方收到。重发的消息会在头部有dup标示。这种QoS能够保证消息不丢,但接收方可能会有重复消息,须要作去重。以下图所示:
QoS 2:有且仅有一次。能够保证不丢不重,可是通讯压力高,须要屡次握手。以下图所示:
3,客户端实现
3.1 消息处理
发送消息比较简单,只须要往某一个topic发布便可。
接收消息的流程以下:
收消息:客户端须要保持一个长链接,而且确保链接稳定,如上章节所示。
消息过滤:若是发送端不能确保消息不重(如mqtt中QoS为0或1),客户端须要作去重,所以消息须要有一个惟一的id。
消息合并和分发:在实际使用场景中,每每有各类各样的消息类型(如聊天消息、系统通知等),对同一类型的消息能够作合并,以加快后续消息处理速度。而不一样类型的消息则分发到各自的处理器当中,如存储到本地数据库,通知页面更新等)
UI更新:客户端通常是使用列表来展现消息(iOS中是UITableView,Android中是ListView),而列表的数据量可能很大,数据源更新频率也可能很频繁,所以须要对列表作性能优化,以确保用户体验。以iOS为例,使用Instruments监控性能瓶颈的地方,对内存占用和CPU占用大户进行优化。肯定问题后,经常使用的技巧有:对cell高度作缓存;简化UI层次结构;避免大量的离屏渲染;减小混合图层;等等。对症下药,各个击破。
3.2 其余
IM应用中,还有不少经常使用的实现需求,例如表情键盘,图片语音等多媒体的存储和下载队列等。但这不在系统实现的范畴中,未来后有文章进行详细阐述。
参考:
https://en.wikipedia.org/wiki/XMPP
http://www.blogjava.net/yongboy/archive/2014/02/15/409893.html