TCP的'粘包'相关
Posted gexiaotian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP的'粘包'相关相关的知识,希望对你有一定的参考价值。
第一篇博客
本博文非专业博文:
另引自百科(百度汉语百科):
粘是多音字,读音为zhān和nián。
读作nián时,词性是形容词,指具有粘性,另外,粘氏原本是女真族。
读作zhān时,词性是动词,指黏的东西互相连接或附着在别的东西上;用胶水或糨糊等把一种东西胶合在另一种东西上。
正文:
本博文主要纠结一点(刚学web,理解浅显):
1.TCP中为何出现‘粘包‘?
2.TCP(transport control protocol,传输控制协议,protocol就是协议的意思,嘿嘿)中的‘粘包‘怎么解决?(...)
一.什么是TCP:
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议.
二."粘包"的前因后果
众所周知,tcp本身是没有"粘包"的,但是因为我们这些小白初学者操作不当导致数据在传输过程中发生粘黏,所以最后接收到的数据不符合我们预期.对于这一现象,大佬们为了让我们易于理解,创造出"粘包"一词(这里的‘包‘并不是真正的数据包的意思,而是一段数据流,以下都称‘包‘,方便省事),这样更方便我们了解和学习,并防止该情况再次发生.该词形象具体,非常适合我们这些非科班出生的小白.
那么"粘包"问题为什么会出现?
原因应该归结于TCP的无边界特性和默认的Nagel算法.
其中TCP的无边界性来自于其是面向字节流传输(个人认为可以理解为水流).
而对于Nagel算法的解释:(摘自Youmai の Blog的《tcp是流的一些思考--拆包和粘包》)
tcp中有一个negal算法,用途是这样的:通信两端有很多小的数据包要发送,虽然传送的数据很少,但是流程一点没少,也需要tcp的各种确认,校验。这样小的数据包如果很多,会造成网络资源很大的浪费,negal算法做了这样一件事,当来了一个很小的数据包,我不急于发送这个包,而是等来了更多的包,将这些小包组合成大包之后一并发送,不就提高了网络传输的效率的嘛。这个想法收到了很好的效果,但是我们想一下,如果是分属于两个不同页面的包,被合并在了一起,那客户那边如何区分它们呢?而这就是所谓的‘粘包‘现象.(这段解释我能理解,所以直接摘下来了)
Nagle算法比较专业的介绍:(摘自网络,很多专有名词看着必然一脸懵逼,可以跳过)
其是一种拥塞控制算法,为了防止网络中充斥着大量的“交互数据”。
1、数据的一次成功的发送,要经过“发送、接收到ACK”。为了尽可能的利用网络带宽,TCP总是希望一次性尽可能的发送足够大的数据(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。
2、Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。
3、Nagle算法的核心思想是最多只能有一个未被确认的小段(所谓“小段”,指的是小于MSS尺寸的数据块)存在于网络,而待发送的其它小分组会被重新分组成一个”较大的”小分组,等收到上一个小分组的应答或长度达到MSS后再发送。
PS: 在TCP传输中每个包的头的长度都是固定的,总长度不能超过MTU(最大传输单元,一般设为1500),且数据长度不能超过MSS(MSS=MTU-20bytes(IP包头)-20bytes(TCP包头)).如果超过了,系统会进行拆包处理.
Nagle算法的初衷:避免发送大量的小包(间隔小&数据小),防止小包泛滥于网络,理想情况下,对于一个TCP连接而言,网络上每次只能一个小包存在。它更多的是端到端意义上的优化。
应对面试官:(严肃脸)
TCP是基于数据流的协议,由于TCP本身的机制(面向连接的可靠地协议-三次握手机制),客户端与服务器会维持一个连接(又叫长连接),数据在连接不断开的情况下,可以持续不断地将多个数据包发往服务器,但是如果发送的网络数据包太小且间隔短,那么他本身会启用Nagle(内格尔,不是‘nige‘,不要乱读)算法(默认启用,可配置是否启用)对较小的数据包进行合并(基于此,TCP的网络延迟要UDP的高些),然后再发送(超时或者包大小足够).那么这样的话,服务器在接收到消息(数据流)的时候就无法区分哪些数据包是客户端自己分开发送的,这样就产生了‘粘包‘.....
三.‘粘包‘的解决(使用模块是python中的内置模块)
问题出现了,自然要想办法解决.TCP本身没有问题,那么问题自然是出现在使用者身上,所以我们还是从自己传输的数据下手,让传输数据的数据信息被计算机先一步知晓即可.
解决步骤:(代码自己写,这里提供一个解决思路)
1.计算传输数据流字节长度,json.dumps后计算len,并用struct.pack打包后传输,这里可指定打包数据长度;
2.发送需要传输的数据字节流;
3.接收端先接收指定长度的数据流,然后用struct.unpack解包,得到所需要接收的数据长度,根据按长度去接收数据即可.
End!!!
PS: 若想更详细的了解,直接移步大佬迎风而来博客: https://www.cnblogs.com/sui776265233/p/9289858.html(我收集相关资料时发现这里写的比我乱七八糟归纳的详细很多...)
以上是关于TCP的'粘包'相关的主要内容,如果未能解决你的问题,请参考以下文章