这两年多一直从事网易云信 iOS 端 IM SDK的开发,期间不断有兄弟部门的同事和合做伙伴过来问各类技术细节,干脆统一介绍下一个IM APP的方方面面,包括技术选型(包括通信方式,网络链接方式,协议选择)和常见问题。(原文连接:http://www.52im.net/thread-133-1-1.html)php
分享者:项望烽,毕业于浙江大学,目前是网易云信 iOS 端研发负责人。 html
- 即时通信开发交流群: 215891622 [推荐]android
- 移动端IM开发推荐文章:《新手入门一篇就够:从零开发移动端IM》算法
IM通信方式无非两种选择:设备直连(P2P)和经过服务器中转。编程
P2P多见于局域网内聊天工具,典型的应用有:飞鸽传书、天网Maze(你懂的)等。这类软件在启动后通常作两件事情:缓存
详细的流程能够参考飞鸽传书源码。可是这种方式在有种种限制和不便:一方面它只适合在线的点对点消息传输,对离线,群组等业务支持不够。另外一方面因为 NAT 的存在,使得不一样局域网内机器互联难度大大上升,在某些网络类型(对称NAT)下没法创建链接。
安全
几乎全部互联网IM产品都采用服务器中转这种方式进行消息传输,相对于P2P的方式,它有以下的优势:服务器
固然它也有本身的问题:服务器架构复杂,并发要求高。微信
IM主流网络通信技术有两种:网络
后者常见于WEB IM系统(固然如今不少WEB IM都是基于WebSocket实现),它的优势是实现简单,方便开发上手,问题是流量大,服务器负载较大,消息及时性没法很好地保证,对大规模的用户量支持不够,比较适合小型的IM系统,如小网站的客户系统。
基于TCP长链接则可以更好地支持大批量用户,问题是客户端和服务器的实现比较复杂。固然也还有一些变种,以下行使用MQTT进行服务器通知/消息的下发,上行使用HTTP短链接进行指令和消息的上传。这种方式可以保证下行消息/指令的及时性,可是在弱网络下上行慢的问题仍是比较严重。早期的来往就是基于这种方式。
IM协议选择原则通常是:易于拓展,方便覆盖各类业务逻辑,同时又比较节约流量。后一点的需求在移动端IM上尤为重要。常见的协议有:XMPP、SIP、MQTT、私有协议。(更多关于即时通信应用的协议选择,请参见《如何选择即时通信应用的数据传输格式》:http://www.52im.net/thread-276-1-1.html)
优势:协议开源,可拓展性强,在各个端(包括服务器)有各类语言的实现,开发者接入方便;
缺点:缺点也是很多,XML表现力弱、有太多冗余信息、流量大,实际使用时有大量天坑。
SIP协议多用于VOIP相关的模块,是一种文本协议,因为我并无实际用过,因此不作评论,但从它是文本协议这一点几乎能够判定它的流量不会小。
优势:协议简单,流量少;
缺点:它并非一个专门为IM设计的协议,多使用于推送。
市面上几乎全部主流IM APP都是是使用私有协议,一个被良好设计的私有协议优势很是明显。
优势:高效,节约流量(通常使用二进制协议),安全性高,难以破解;
缺点:在开发初期没有现有样列能够参考,对于设计者的要求比较高。
一个好的协议须要知足以下条件:高效,简洁,可读性好,节约流量,易于拓展,同时又可以匹配当前团队的技术堆栈。基于如上原则,咱们能够得出: 若是团队小,团队技术在IM上积累不够能够考虑使用XMPP或者MQTT+HTTP短链接的实现。反之能够考虑本身设计和实现私有协议。
移动互联网相对于有线网络最大特色是:带宽低,延迟高,丢包率高和稳定性差,流量费用高。因此在私有协议的序列化上通常使用二进制协议,而不是文本协议。
常见的二进制序列化库有protobuf和MessagePack,固然你也能够本身实现本身的二进制协议序列化和反序列的过程,好比蘑菇街的TeamTalk。可是前面两者不管是可拓展性仍是可读性都完爆TeamTalk(TeamTalk连Variant都不支持,一个int传输时固定占用4个字节),因此大部分状况下仍是不推荐本身去实现二进制协议的序列化和反序列化过程。
基于TCP的应用层协议通常都分为包头和包体(如HTTP),IM协议也不例外。包头通常用于表示每一个请求/反馈的公共部分,如包长,请求类型,返回码等。 而包头则填充不一样请求/反馈对应的信息。
一个最简单的包头能够定义为:
1
2
3
4
5
6
7
|
struct
PackHeader
{
int32_t length_;
//包长度
int32_t serial_;
//包序列号
int32_t command_;
//包请求类型
int32_t code_;
//返回码
};
|
以心跳包为例,假设当前的serial为1,心跳包的command为10,那么使用MessagePack作序列化时:length=4,serial=1,command=10,code=0,每一个字段各占一个字节,包体为空,仅须要4个字节。
固然这是最简单的一个例子,面对真正的业务逻辑时,包体里面会须要塞入更多地信息,这个须要开发根据本身的业务逻辑总结公共部分,如为了兼容加入的协议版本号,为了负载均衡加入的模块id等。
上面的内容就是一个IM系统大体的选型过程:服务方式,网络通信协议,数据通讯协议选择、协议设计。可是实际开发过程当中还有大量的问题须要处理。
为了保证协议不容易被破解,市面上几乎全部主流IM都会对协议进行加密传输。常见的流程和HTTPS加密类似:创建链接后,客户端和服务器进行进行协商,最终客户端得到一个当前Sessino的秘钥,后续的数据传输都经过这个秘钥进行加解密。通常出于效率的考虑都会采用流式加密,如RC4。而前期协商过程则推荐使用RSA等非对称加密以增长破解难度。
对iOS APP而言,由于没有真后台的存在,APP每次启动基本都须要一次重连登陆(短期内切换除外),因此如何快速重连、重登就很是重要。
常见优化思路以下:
通常APP实现链接保持的方式无非是采用应用层的心跳,经过心跳包的超时和其余条件(网络切换)来执行重连操做。那么问题来了:为何要使用应用层心跳和如何设计应用层心跳。众所周知TCP协议是有KEEPALIVE这个设置选项,设置为KEEPALIVE后,客户端每隔N秒(默认是7200s)会向服务器发送一个发送心跳包。
但实际操做中咱们更多的是使用应用层心跳。缘由以下:
移动端在实际操做时为了节约流量和电量通常会在心跳包上作一些小优化:
在移动网络下,丢包,网络重连等状况很是之多,为了保证消息的可达,通常须要作消息回执和重发机制。参考易信,每条消息会最多会有3次重发,超时时间为15秒,同时在发送以前会检测当前链接状态,若是当前链接并无正确创建,缓存消息且定时检查(每隔2秒检查一次,检查15次)。因此一条消息在最差的状况下会有2分钟左右的重试时间,以保证消息的可达。
由于重发的存在,接受端偶尔会收到重复消息,这种状况下就须要接收端进行去重。通用的作法是每条消息都戴上本身惟一的message id(通常是uuid)。
IM消息(包括SNS模块)内包含大量的文件上传的需求,如何优化文件的上传就成了一个比较大的主题。
常见有下面这些优化思路:
(原文连接:http://www.52im.net/thread-133-1-1.html)
[1] 网络编程基础资料:
《TCP/IP详解 - 第11章·UDP:用户数据报协议》
《TCP/IP详解 - 第17章·TCP:传输控制协议》
《TCP/IP详解 - 第18章·TCP链接的创建与终止》
《TCP/IP详解 - 第21章·TCP的超时与重传》
《理论经典:TCP协议的3次握手与4次挥手过程详解》
《理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程》
《计算机网络通信协议关系图(中文珍藏版)》
《NAT详解:基本原理、穿越技术(P2P打洞)、端口老化等》
《UDP中一个包的大小最大能多大?》
《Java新一代网络编程模型AIO原理及Linux系统AIO介绍》
《NIO框架入门(三):iOS与MINA二、Netty4的跨平台UDP双向通讯实战》
《NIO框架入门(四):Android与MINA二、Netty4的跨平台UDP双向通讯实战》
>> 更多同类文章 ……
[2] 有关IM/推送的通讯格式、协议的选择:
《为何QQ用的是UDP协议而不是TCP协议?》
《移动端即时通信协议选择:UDP仍是TCP?》
《如何选择即时通信应用的数据传输格式》
《强列建议将Protobuf做为你的即时通信应用数据传输格式》
《移动端IM开发须要面对的技术问题(含通讯协议选择)》
《简述移动端IM开发的那些坑:架构设计、通讯协议和客户端》
《理论联系实际:一套典型的IM通讯协议设计详解》
《58到家实时消息系统的协议设计等技术实践分享》
>> 更多同类文章 ……
[3] 有关IM/推送的心跳保活处理:
《Android进程保活详解:一篇文章解决你的全部疑问》
《Android端消息推送总结:实现原理、心跳保活、遇到的问题等》
《为什么基于TCP协议的移动端IM仍然须要心跳保活机制?》
《微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)》
《微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)》
《移动端IM实践:实现Android版微信的智能心跳机制》
《移动端IM实践:WhatsApp、Line、微信的心跳策略分析》
>> 更多同类文章 ……
[4] 有关WEB端即时通信开发:
《新手入门贴:史上最全Web端即时通信技术原理详解》
《Web端即时通信技术盘点:短轮询、Comet、Websocket、SSE》
《SSE技术详解:一种全新的HTML5服务器推送事件技术》
《Comet技术详解:基于HTTP长链接的Web端实时通讯技术》
《WebSocket详解(一):初步认识WebSocket技术》
《socket.io实现消息推送的一点实践及思路》
>> 更多同类文章 ……
[5] 有关IM架构设计:
《浅谈IM系统的架构设计》
《简述移动端IM开发的那些坑:架构设计、通讯协议和客户端》
《一套原创分布式即时通信(IM)系统理论架构方案》
《从零到卓越:京东客服即时通信系统的技术架构演进历程》
《蘑菇街即时通信/IM服务器开发之架构选择》
《腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT》
《微信技术总监谈架构:微信之道——大道至简(演讲全文)》
《如何解读《微信技术总监谈架构:微信之道——大道至简》》
《快速裂变:见证微信强大后台架构从0到1的演进历程(一)》
《17年的实践:腾讯海量产品的技术方法论》
>> 更多同类文章 ……
[6] 有关IM安全的文章:
《即时通信安全篇(一):正确地理解和使用Android端加密算法》
《即时通信安全篇(二):探讨组合加密算法在IM中的应用》
《即时通信安全篇(三):经常使用加解密算法与通信安全讲解》
《即时通信安全篇(四):实例分析Android中密钥硬编码的风险》
《传输层安全协议SSL/TLS的Java平台实现简介和Demo演示》
《理论联系实际:一套典型的IM通讯协议设计详解(含安全层设计)》
《微信新一代通讯安全解决方案:基于TLS1.3的MMTLS详解》
《来自阿里OpenIM:打造安全可靠即时通信服务的技术实践分享》
>> 更多同类文章 ……
[7] 有关实时音视频开发:
《即时通信音视频开发(一):视频编解码之理论概述》
《即时通信音视频开发(二):视频编解码之数字视频介绍》
《即时通信音视频开发(三):视频编解码之编码基础》
《即时通信音视频开发(四):视频编解码之预测技术介绍》
《即时通信音视频开发(五):认识主流视频编码技术H.264》
《即时通信音视频开发(六):如何开始音频编解码技术的学习》
《即时通信音视频开发(七):音频基础及编码原理入门》
《即时通信音视频开发(八):常见的实时语音通信编码标准》
《即时通信音视频开发(九):实时语音通信的回音及回音消除概述》
《即时通信音视频开发(十):实时语音通信的回音消除技术详解》
《即时通信音视频开发(十一):实时语音通信丢包补偿技术详解》
《即时通信音视频开发(十二):多人实时音视频聊天架构探讨》
《即时通信音视频开发(十三):实时视频编码H.264的特色与优点》
《即时通信音视频开发(十四):实时音视频数据传输协议介绍》
《即时通信音视频开发(十五):聊聊P2P与实时音视频的应用状况》
《即时通信音视频开发(十六):移动端实时音视频开发的几个建议》
《即时通信音视频开发(十七):视频编码H.26四、V8的前世此生》
《简述开源实时音视频技术WebRTC的优缺点》
《良心分享:WebRTC 零基础开发者教程(中文)》
>> 更多同类文章 ……
[8] IM开发综合文章:
《移动端IM开发须要面对的技术问题》
《开发IM是本身设计协议用字节流好仍是字符流好?》
《请问有人知道语音留言聊天的主流实现方式吗?》
《IM系统中如何保证消息的可靠投递(即QoS机制)》
《谈谈移动端 IM 开发中登陆请求的优化》
《彻底自已开发的IM该如何设计“失败重试”机制?》
《微信对网络影响的技术试验及分析(论文全文)》
《即时通信系统的原理、技术和应用(技术论文)》
《开源IM工程“蘑菇街TeamTalk”的现状:一场虎头蛇尾的开源秀》
>> 更多同类文章 ……
[9] 开源移动端IM技术框架资料:
《开源移动端IM技术框架MobileIMSDK:快速入门》
《开源移动端IM技术框架MobileIMSDK:常见问题解答》
《开源移动端IM技术框架MobileIMSDK:压力测试报告》
>> 更多同类文章 ……
[10] 有关推送技术的文章:
《iOS的推送服务APNs详解:设计思路、技术原理及缺陷等》
《Android端消息推送总结:实现原理、心跳保活、遇到的问题等》
《扫盲贴:认识MQTT通讯协议》
《一个基于MQTT通讯协议的完整Android推送Demo》
《求教android消息推送:GCM、XMPP、MQTT三种方案的优劣》
《移动端实时消息推送技术浅析》
《扫盲贴:浅谈iOS和Android后台实时消息推送的原理和区别》
《绝对干货:基于Netty实现海量接入的推送服务技术要点》
《移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)》
《为什么微信、QQ这样的IM工具不使用GCM服务推送消息?》
>> 更多同类文章 ……
[11] 更多即时通信技术好文分类: