博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
移动端IM系统的协议选型:UDP还是TCP?
阅读量:5050 次
发布时间:2019-06-12

本文共 3721 字,大约阅读时间需要 12 分钟。

1、前言

对于有过网络编程经验的开发者来说,使用何种数据传输层协议来实现数据的通信,是个非常基础的问题,它涉及到你的第一行代码该如何编写。

从PC时代的IM开始,IM开发者就在为数据传输协议的选型争论不休(比如:《》这样的问题,隔一段时间就能在社区里看到)。到了移动互联网时代,鉴于移动网络的不可靠性等特点,再加上手机的省电策略、流量压缩等,为这个问题的回答增了更多的不确定因素。
对于有选择困难证的人来说,基于以上因素,加上UDP和TCP协议的本质差异,这样的选择确实很纠结。本文将从作者的实践总结,给出自已的观点,如有异议还请理性回复,不为找喷,仅供参考。
说明:本文引用了DDPush的技术资料,感谢原作者。 

2、学习交流 

- 即时通讯开发交流群:  [推荐]

- 移动端IM开发推荐文章:《》

3、UDP vs TCP

TCP还是UDP?长连接如何实现?如何实现心跳机制?心跳的间隔如何确定?这些问题都是讨论移动端IM、消息推送等类似话题时,几乎一定被问到的问题。这里尝试正本清源一下。

4、互联网、移动互联网网络环境

在分析到底应该使用UDP还是TCP之前,有必要先讨论一下互联网与移动互联网的网络环境特点。

互联网的网络基础建设,经过十几年长期的发展,已经较为稳定和成熟,PC终端、操作系统的能力也达到了较高的水平。
而移动互联网,由于涉及到无线电话网络基站、2G、3G和4G技术的不断发展,其稳定性、带宽、资源分配等各方面虽日趋完善,但当前终究还有不少问题的存在。另外,由于移动互联网其“移动”的本质,加上智能终端设备(智能手机、平板电脑)的发展较晚,目前还在不断演变的情况,与互联网相比,移动互联网还是低速、不稳定、终端能力稍弱的情况。而且由于其“移动”本质,短时间内很难达到互联网的质量。
所以,在互联网的环境里面,网络应用程序由于网络设施、操作系统的成熟,开发使用起来比较容易,资源也较为充足。而移动互联网还是要“斤斤计较”。

5、智能终端电池续航能力,系统休眠

智能终端设备的电池续航能力始终是技术瓶颈。在连续使用的情况下,绝大部分智能设备电池无法支持两个小时以上。所以在没有外部电源的情况,智能终端设备必须频繁、长时间休眠,这将极大地影响两种网络环境下的网络应用场景。

6、IPv4资源、端口资源

这个话题往往被很多人忽略,但它有着至关重要的影响。虽然大部分人都很清楚IP地址的紧缺导致的动态IP分配的必然,却忽略了由于IP地址不足引起的端口资源不足。

由于需要动态分配IP地址(这里不仅仅指互联网入口的IP,还包括局域网内部的IP),路由器的工作原理都是经过端口映射,把内部网络(包括PC、手机、平板、Wifi、2G、3G、4G)IP与端口映射成外部IP(通常是公网IP)和对应的端口,并维持这个映射关系,才能正常地修改、转发报文信息,保证内部各个ip、端口与外部的各个ip、端口的通信。
然而,单个IP地址的端口资源是有限的,理论上限是65535个端口。对于普通宽带路由器来说,这个已经很充足了。但是!对于大型的网络服务、网络主干接入点等来说,如果IP资源不足,每个IP几万个端口的资源很快会耗尽,从而影响正常通讯。(有关NAT技术原理,请参见《》)

7、端口映射老化时间

正因为如此,所有的路由器都会为每个端口映射关系设置老化时间,如果老化时间倒数到0,则端口映射关系失效,该端口被释放给其他连接使用。如果端口全部耗尽,则无法再新建内部与外部的网络连接。

端口映射老化时间,比很多人想象中的要短很多。一般的家用宽带路由器,老化时间一般是两三分钟;在有线宽带运营商接入部分,老化时间可能少于两分钟。在无线电话网络运营商接入部分(例如GPRS连接),老化时间甚至不超过一分钟!
也就是说,任何一个网络通讯(不管是TCP或UDP),如果几分钟之内没有网络报文传输,其占用的IP地址端口将被路由器回收。这个时候该次通信必将终止,不管TCP还是UDP,神马都是浮云。
更残酷的事实是,互联网可认为是由无数个路由器连接而成的,一个网络通信往往需要通过n个路由器,每个路由器都会为一次通信建立自己的端口映射。只要其中一个路由器回收其端口,则整个通讯中断。
这也是很多人疑惑为什么TCP的KeepAlive参数无法保证长连接的原因。TCP的KeepAlive默认是两个小时(而且该参数还是TCP的可选实现,不是必然实现),在路由器端口映射老化时间的影响下,必然无法发挥其作用。实际上,该参数在单一的局域网内才可能被使用上,还要依赖具体的操作系统。
由于路由器端口映射的存在,加上智能终端频繁、长时间的休眠,TCP长连接的实用性在移动互联网情况下极大地打了折扣。
也因为如此,移动端IM、推送系统必须实现所谓的心跳包机制,以保持端口映射关系的老化时间不会减少到0而被回收,从而避免连接中断。(有关TCP协议下的心跳问题,请参见:《》)

8、服务端承载能力

不管是UDP还是TCP,最终都是应用服务端的设备去提供服务的。而TCP由于提供了安全可靠的流服务,其对计算机、网络资源的消耗是远远大于UDP协议的。对于配置较好的主流服务器,配备大量的内存(数十G至上百G内存),与高速的磁盘、网卡,是能同时支持数百万个TCP连接的。不过这里需要较专业的服务器设置,需要调整不少系统参数,再加上服务程序的配合。另外,TCP连接的建立、维持与释放,都是需要较昂贵的计算、网络资源的。

终端在线服务,若是一个较为简单的服务,未必使用上TCP众多的高级功能,但承受TCP的昂贵成本,未必值得。如果能用UDP来提供服务,单服务器的承载能力,是可以去到TCP服务的数十倍,甚至上百倍的增长。这也是为什么DNS这种并发数巨大的服务器提供UDP接口的原因。
另外,上百万TCP连接的网络服务,其编程的难度、程序复杂度、调试难度、服务器运维成本、网络成本等都远远高于UDP。
而UDP编程,与上百万个终端通讯的难度与成本则低很多。如果提供的网络服务不是基于流的服务,也允许一定的失败机率(例如P2P),则UDP往往是更适合的方式。

9、高级应用网络通讯要求

不过,移动端IM系统、推送系统一方面提供终端在线服务,另外一方面也需要考虑内容信息的完整性和安全性。毕竟信息的丢失,或者通讯的被窃听,都是难以接受的。而TCP不管在网络层的可靠性控制,还是在应用层的安全支持(例如HTTPS),都为应用提供无法替代的强大功能和便利。

10、结论

综合以上所述,其实答案也呼之欲出。

现在的移动端IM、推送系统,既面对移动互联网的不确定性,又面对智能终端频繁的系统休眠、网络切换,还要考虑服务端的承载成本,对于在线服务而言UDP是比TCP更适合的方式。但是由于数据完整性、安全性的需要,又不应完全放弃TCP的可靠与安全。
所以,个人认为,更恰当的方式应该是:两种通信协议同时使用,各有侧重。UDP用于保持大量终端的在线与控制,应用与业务则通过TCP去实现。这个和FTP服务控制与数据分离,采取不同的连接,有异曲同工之处。
事实上,这个也是即时通讯巨头QQ所采用的方式。早期的时候,QQ还是主要使用TCP协议,而后来就转向了采用UDP的方式来保持在线,TCP的方式来上传和下载数据。现在,UDP是QQ的默认工作方式,表现良好。相信这个也被沿用到了微信上。
简单的考证:登录PC版QQ,关闭多余的QQ窗口只留下主窗口,并将其最小化。几分钟过后,查看系统网络连接,会发现QQ进程已不保有任何TCP连接,但有UDP网络活动。这时在发送聊天信息,或者打开其他窗口和功能,将发现QQ进程会启用TCP连接。

11、参考资料

《》

《》
《》
《》
《》
《》
《》

(本文同步发布于:

 

附录:更多IM技术文章 

[1] 网络编程基础资料:

《 - 》

《 - 》

《》

《》

《》

《》

 

《》

《》

《》

>> 

[2] 有关IM/推送的通信格式、协议的选择:

《》

《》

《》

《》

《》

《》

《》

《》

>> 

[3] 有关IM/推送的心跳保活处理:

《》

《》

《》

《》

《》

《》

《》

>> 

[4] 有关WEB端即时通讯开发:

 

《》

《》

《》

《》

《》

>> 

[5] 有关IM架构设计:

《》

 

《》

《》

《》

《》

《》

《》

《》

《》

>>  

[6] 有关IM安全的文章: 

《》

《》

《》

《》 

《》

 

《》

《》

>>  

[7] 有关实时音视频开发: 

《》

 

《》

《》

《》 

 

《》

《》

《》

《》

《》

《》

《》

《》

《》

《》

《》

《》

《》 

>> 

[8] IM开发综合文章:

《》

《》 

《》

《》 

《》

《》

《》

《》

《》

>>  

[9] 开源移动端IM技术框架资料:

《》

《》 

《》

>> 

[10] 有关推送技术的文章:

《》

《》

《》

《》

《》

《》

《》

《》

《》

《》

>> 

[11] 更多即时通讯技术好文分类:

 

转载于:https://www.cnblogs.com/jb2011/p/5778680.html

你可能感兴趣的文章
面向对象1
查看>>
在ns2.35中添加myevalvid框架
查看>>
【贪心+DFS】D. Field expansion
查看>>
为什么要使用href=”javascript:void(0);”
查看>>
二进制文件的查看和编辑
查看>>
C# Async与Await的使用
查看>>
Mysql性能调优
查看>>
iOS基础-UIKit框架-多控制器管理-实例:qq界面框架
查看>>
javascript学习---BOM
查看>>
IOS-每个程序员的编程之路上都应该看这11本书
查看>>
自定义tabbar(纯代码)
查看>>
extjs fieldset 和 radio
查看>>
小程序底部导航栏
查看>>
Codeforces Gym101505G:Orchard Division(扫描线+线段树第k大)
查看>>
ibatis学习笔记
查看>>
18-ES6(1)
查看>>
poj1611 简单并查集
查看>>
tensorflow实现迁移学习
查看>>
Ubuntu 14.04下安装CUDA8.0
查看>>
跨平台开发 -- C# 使用 C/C++ 生成的动态链接库
查看>>