一个网络开发中错误的词汇--"粘包"

    首先想说一下为什么突然想说起TCP网络连接中经常听到的这个词,原因是最近我在做一个基于局域网连接的AR应用,而这就需要实现一套基于TCP协议的网络通信框架,在实现这个框架的时候,少不了要解决所谓“粘包”的问题,说来也有趣,年前的时候,我的一个程序员交流群里,刚刚因为“粘包”这个词产生过一次争论,而争论的说法也许会颠覆你原先的认知,就是:到底有没有“粘包”这个说法,这个词儿本身是否有问题。也许刚开始你会很惊讶,因为通常来说,一个做过网络开发的程序员可能去面试的时候,都会经常被面试官问到“粘包”这个技术问题,甚至一些老师在讲课的时候也会提到“粘包”这个词,关于这个问题,我比较赞同知乎的https://www.zhihu.com/question/20210025 这个问题里谢狄的回答,那么接下来我想说说自己的一点看法。
    “粘包”这个词到底是谁发明的,已经不得而知了,但是这个词所想表达的问题倒是确实存在,但不应该叫“粘包”,得益于这次要做一个局域网通信框架,我又回过头去好好的复习了一下网络协议,说实话,学生时代很多时候这些概念只是死记硬背,为了应付考试,即使刚刚工作可能也只是热衷于具体的实现和问题的解决,比如你只关心我能建立TCP连接,能正常收发数据,解析数据就行了,而不会去真正关心这个问题本身,那么我们来回顾一下网络协议。书上明确说TCP,UDP协议是属于七层网络协议里的传输协议,TCP的数据传输是基于“流”的。既然是基于流的传输,又哪里有”包“这个概念,既然没有”包“的概念,又何来”粘包“一词呢?UDP倒是有数据包一说,因为他就是数据报协议,它发送的就是一个一个的”包“,但也因为它是一个一个发送的,那边也是一个一个接受的,它不存在”粘包“这个说法。而通常我们所说的”包“其实是我们自己定义的,其实本质是属于七层网络协议里面的应用层协议,为什么,因为我们在网络传输中关心的是从TCP流里发过来的这些数据我们怎么合理利用的问题,所以像HTTP协议就是应用层协议的一种,它定义了自己的消息的结构,然后我们按照这个结构去解析数据,就是HTTP协议,那我们也可以定义自己的协议(例如”包“)比如我们都希望自己的数据是一条一条的。但由于TCP的流式传输,它可不懂你的协议,它只管一直发数据,你怎么把它分成你自己想要的一条一条的有用的数据,所以这个过程中,你需要解决的这个问题被很多人称为”粘包“。而在我看来,其实它的本质是”数据分割“。正如我刚才所说你怎么把这个流里面传入过来的数据,按照你定义的协议去把它分割成一条条你需要的数据,这个才是关键。
    说完了我个人的理解,下面再以我这次实现的网络通讯的框架为例,来说说我是怎么分割的,比如,我希望我的每条数据都是一条json结构的数据,那数据通过”流“传过来我怎么分割呢,那么我先定义一个固定的长度,比如4个字节,我们用它来存储我这条数据到底有多长,我们称之为”包头“,接下来就是我们真正的json数据,我们称之为”包体“,每次发送数据的时候都是包头+包体的方式发过去,那么接收时我们每次从流里面读取到数据做什么呢,我们就先看第一次读够4个字节了没,因为头四个字节是头,它存着我们整个包有多长,它都没读取完,我们怎么知道接下来到底要读多长,才算一条完整的数据呢?所以如果我们读够了4个字节了,我们先解析一下,看看这4个字节存储的我们这条数据的长度有多少,知道了这条数据总长度是多少,接下来就好办了,我们就继续读数据,由于我们知道了我们这条数据有多长了,那么我们就判断呗,如果够了长度,我们就组织成一条完整的数据,如果长度不够这条数据的,那就接着继续读呗。这个其实就是平时很多人所说的解决”粘包“的方式,网上实在例子太多,不同语言的版本也有,我就不列出代码了。
    现在回过头来再说说”粘包“这个词,其实发明这个词的人本身有些误解,问题是有,但是不该这么叫,但是既然这么叫了,也流传开来了,那没办法了,可能有时沟通时只能适应,比如面试官非要问你”粘包“,你可能也不好意思先把面试官怼一遍,告诉他你说”粘包“不对!所以当别人以后说起”粘包“的时候你知道它在说啥就行了,不比过于纠结这个词本身,但是说实话,我还是不认同管这个问题叫做”粘包“的,正如经典游戏《The Last Of US》有人翻译成《最后的我们》,有人翻译成《美国末日》,日本国民级RPG游戏《Dragon Quest》被翻译成《勇者斗恶龙》,所以一个错误的翻译或者词汇被流传,其实很多很多,我们不比过于纠结,只要下次你听到这个词你知道它说的是啥就行了。

fantasycoding.net 2016-2024 © All rights Reserved京ICP备2020039454号-1