TCP 粘包,拆包

 

概念:

TCP是个“流”式的协议,所谓流,就像河里的水,中间没有边界。TCP传输的数据,在网络上就是一连串的数据,没有分界线。TCP协议的底层,并不了解上层业务的具体定义,它会根据TCP缓冲区的实际情况进行包的划分。在业务层面认为一个完整的包,可能会被TCP拆分成多个小包进行发送,也可能把多个小的包封装成一个大的数据包进行发送,这就是所谓的TCP粘包拆包问题。

客户端发送了两个数据包P1和P2给服务端,服务端一次读取到的字节数是不确定的,可能存在以下4种情况:

java netty 查看tcp断连原因_网络

客户端发送了两个数据包P1和P2给服务端,服务端一次读取到的字节数是不确定的,可能存在以下4种情况:

(1)服务端分两次读取到了两个独立的数据包P1和P2,没有发送粘包和拆包;
(2)服务端一次读到了两个数据包,P1和P2粘在一起,这就是TCP粘包情况;
(3)服务端分两次读取到了两个数据包,第一次读取了完整的P1包和P2包的一部分,第二次读取到了P2包的剩余部分,这被称为TCP拆包;
(4)服务端分两次读取了两个数据包,第一次读取了P1包的一部分,第二次读取到了P1包的剩余部分,这也是TCP拆包;

粘包和拆包的代码演示

java netty 查看tcp断连原因_TCP_02

java netty 查看tcp断连原因_nio_03

TCP粘包/拆包发生的原因

TCP 协议是面向连接的、可靠的、基于字节流的传输层 通信协议,是一种流式协议,消息无边界。

TCP数据流最终发到目的地,需要通过以太网协议封装成一个个的以太网帧发送出去,以太网数据帧大小最小64字节,最大1518字节,除去header部分,其数据payload为46到1500字节。所以如果以太网帧的payload大于MTU(默认1500字节)就需要进行拆包。

粘包拆包问题解决方法

java netty 查看tcp断连原因_网络协议_04

Netty如何解决粘包拆包问题


Netty提供了针对封装成帧这种形式下不同方式的拆包器,所谓的拆包其实就是数据的解码,所谓解码就是将网络中的一 些原始数据解码成上层应用的数据,那对应在发送数据的时候要按照同样的方式进行数据的编码操作然后发送到网络中


java netty 查看tcp断连原因_tcp/ip_05


分隔符解码器-LineBasedFrameDecoder



java netty 查看tcp断连原因_网络协议_06

分隔符解码器-DelimiterBasedFrameDecoder

java netty 查看tcp断连原因_tcp/ip_07

基于长度的域解码器-LengthFieldBasedFrameDecoder

服务端:

java netty 查看tcp断连原因_网络_08

Ø lengthFieldOffset:length域的偏移,正常情况下读 取数据从偏移为0处开始读取,如果有需要可以从其 他偏移量处开始读取

Ø lengthFieldLength:length域占用的字节数

Ø lengthAdjustment:在length域和content域中间是否需要填充其他字节数


Ø initialBytesToStrip :解码后跳过的字节数


客户端:

java netty 查看tcp断连原因_tcp/ip_09

其他解码器


Netty中提供了ByteToMessageDecoder的抽象实现,自定义解码器只需要继承该类,实现decode()即可。Netty也提供 了一些常用的解码器实现,用于数据入站的解码操作,基本都是开箱即用的;当然数据出站也需要采用对应的编码器



java netty 查看tcp断连原因_TCP_10