一、介绍
在程序的开发中,网络开发是一个重要的应用场景。毕竟这些年IT行业之所以火,主要还是互联网(移动互联网)带来的。网络开发,有各种平台、框架以及系统和库提供的API,如果说网络开发是一个特别复杂和困难的场景(前提了高并发等以上的场景),估计做过这类项目和有过接触的开发人员都会赞同。
本文不介绍网络开发中的各种异常、问题以及一些开发经验,只从设计的角度分析一下,网络开发人员经常提到的网络数据包(指TCP/IP)的粘包和分包的情况。
二、粘包和分包
从TCP/IP的设计角度看,做为一种数据流的传输,根本就没有什么 粘包和分包的问题。所谓粘包和分包其实是面向应用层的一种说法,而UDP的开发中由于协议本身设计和消息传输的特性不存在这类问题。给大家举一个例子,大家都有过快递收发的经验,大家会认为自己发送一个小快递(比如一件衣服),快递公司会专门安排一辆车给你送到客户手中么?反过来来也一样,要发送一个非常多的成套的产品,快递公司也不会因为这个去购买一个更大的车去运送而是会根据情况将其拆开用多辆车来发送。明白了这个,就明白了网络包为什么会有粘包和分包了。
TCP/IP发送为了兼顾效率和性能,在处理一些小数据包比如IM通信中的互相打招呼发个字母时,就会合并其它的一些数据再发送;而如果双方发送一些大数据时(不考虑单独传输),又会拆开为多个包进行发送。而不同的平台和系统可能网络的缓冲区也有所不同,那么接收到的数据就可能需要进行拆分,恢复成小的包或等待数据最终形成一个完整的包。
这个在前面分析Nagle算法时,给大家分析过。
三、如何处理
那么在设计上如何应对这种情况呢?
首先,在数据传输的格式上,就要考虑IP包的大小,与其尽量适配(比如固定大小)。不要设计出过大或过小的包,但这样做也有其缺点,比如不灵活,小包浪费带宽等等。
其次,对网络的原始通信配置进行修改,比如禁止诸如Nagle算法的应用,但这样做的缺点是可能导致一些性能上的损失。
最后,设计一些规则,允许网络通信中对粘包和分包不敏感,比如自描述的数据,网络只需将数据保存成功即可,不考虑数据包的内容。同样,这样做的缺点一个是场景应用有限,另外引入了额外的复杂性。
不过话说回来,网络的应用千差万别,光从设计上是无法完全处理粘包和分包的,只能说是尽量完善。最终对其的处理,仍然需要开发者自行进行相关的数据处理。或者可以这样理解,解决粘包这类问题,是要进行整体上的考虑的,在设计上、协议栈上和缓冲区以及应用层的处理上等等进行一个全面的处理和解决。
四、总结
这里只是从设计角度对粘包和分包进行了处理,而诸如常见的在开发的层次进行处理如增加分隔符、自定义格式(消息头/消息体)等等这些都没有讨论。之所以这样,目的就是让大家明白设计在抽象层面的作用与实际开发层面的作用的不同。
很多东西不是简单的一刀就能切开,往往是你中有我,我中有你。但在设计得的心中,得有设计这个抽象的想法一直存在!