龙空技术网

TCP粘包、断包产生的原因及解决方案

九天银河888 416

前言:

现在小伙伴们对“tcp的快速恢复”大体比较关心,小伙伴们都需要剖析一些“tcp的快速恢复”的相关内容。那么小编也在网上网罗了一些有关“tcp的快速恢复””的相关资讯,希望咱们能喜欢,兄弟们一起来了解一下吧!

前言

刚参加工作那会,妥妥的技术小白一枚。有一次领导交了个任务,要让做一个聊天工具,要求还要能够传文件。当时我初生牛犊不畏虎,信心满满地接下了这个任务。结果一上来就碰了一鼻子灰,经过很多不眠夜晚,终于交了差。今天就聊一聊当时我遇到的主要的问题,粘包、断包问题。

什么是TCP粘包、断包现象

我们都知道,网络中传输数据要用socket,socket在发送或者接收过程中只从缓冲区取数据。假如发送端缓冲区大小设置为1k,接收端缓冲区大小设置为2k,那么发送端就1K、1K的发数据,而接收端就2k、2k的收数据。由于网络延迟或者计算机性能等原因,很容易造成收发过程不同步。如果发的快,接的慢,就有可能把发送方两个1k数据包一块接收了,这就造成了粘包现象。断包为相反的现象。

当然在实际应用中还有一种情况,发送方发出数据后,因网络延迟等情况,没收到接收端的确认信息。发送端会认为包丢失,就会重新发送,这样有可能客户端会收到两个一样的数据包,客户端要丢弃一个。

TCP粘包、断包产生的原因

产生这个问题的原因是TCP协议自身造成的,但TCP没有消息边界,TCP为提高传输效率,发送方往往要收到足够多的数据后才发送一个TCP字段。若连续几次需要send的数据很少。通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。发送端或者接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生断包或者粘包。TCP粘包、断包产生的原因解决办法发送端给每个数据包添加包首部。

首部中应该至少包含数据包的长度,在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。在传输文件中,首部还要加上文件总长度、总包数以及包序号。这种方法虽然实现较为复杂,本文主要讲解这种方式。发送端将每个数据包封装为固定长度

如果不够固定的可以通过补0填充,这样接收端每次从接收缓冲区中读取固定长度的数据。但这种方式增加了不必要的数据传输,所以不推荐这种方案。在数据包之间设置边界

在数据包中设置特殊符号,接收端通过特殊符号就可以将不同的数据包拆分开。这种情况客户端很难知道特殊符号是边界还是要发送的数据,所以不推荐这种方案。实现方式

自定义协议

命令,byte,0到255的正整数,作为命令标志;参数,byte,0到255的正整数,作为参数标志;数据长度,int,表示当前包数据长度总包数,int,文件传输时使用包序号,int,文件传输时使用数据正文,byte[],发送的全部数据内容消息体的字节多余数据,byte[],下面详细讲解使用的情况

协议说明

消息发送方封装消息协议类。消息命令和参数需要与接收方约定清楚。消息发送方再将消息“装入”消息协议类的数据正文属性进行发送。消息接收方接收到消息发送方发来的byte[]时,先判断这个byte[]长度是否大于消息命令、参数、数据长度、总包数、包索引的字节长度之和。如果byte[]长度小于前面的长度之和,说明暂时还未收到有效的完整消息,则消息接收方就跳过本次循环,进入下一次继续循环累积接收数据。消息接收方接收到消息发送方发来的byte[]长度如果大于等于这个长度之和,则将byte[]还原为消息协议类对象,可以由此解读出数据正文所需要的数据长度;如果在接收数据时,根据协议已接收完毕,但缓冲区仍然有数据,就要要放到多余数据。这个多余数据说明是下一个数据包的包头,要与下一个包拼接在一块进行解包。在文件传输过程中,要加上包总数和包序号。因为在传输过程中客户端不知道文件的大小,文件的结束位置在哪里。在网络延迟和性能等问题的影响下,有可能先发送的数据包,反而后被客户端接收。所以基于这些原因,加上包序号后就能顺利地把包拼接出来还原成文件,当包序号等于总包数的时候就知道文件传输完成了。

有兴趣的小伙伴可以尝试实现一下吧!

每天一个小知识,每天进步一点点!!![加油][加油][加油]

标签: #tcp的快速恢复 #java socketchannel粘包处理 #socket接收缓冲区满了 #tcp缓冲区什么原因会满 #tcp缓存区管理引起的内存