Netty——解决TCP粘包、拆包
TCP是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发给接收端的包,更有效的发给对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样做虽然提高了效率,但是接收端就难于分辨出完整的数据包了,因为面向流的通信是无消息保护边界的。
由于TCP无消息保护边界, 需要在接收端处理消息边界问题,也就是我们所说的粘包、拆包问题。
假设客户端分别发送了两个数据包D1和D2给服务端,由于服务端一次读取到字节数是不确定的,故可能存在以下四种情况:
特别要注意的是,如果TCP的接受滑窗非常小,而数据包D1和D2比较大,很有可能会发生第五种情况,即服务端分多次才能将D1和D2包完全接受,期间发生多次拆包。
解决问题的根本手段就是找出消息的边界 。
Netty提供了以下三种方式解决TCP粘包和拆包问题:
DelimiterBasedFrameDecoder是通过发送方每条报文结束都添加特殊符号( $_ ) 作 为 报 文 分 隔 符,接收方通过特殊符号( $_ )对报文进行切割。
发送方需要自行编码,添加分隔符,编码如下:
接收方的解码如下:
缺点:发送的内容本身可能会出现分隔符,需要对发送的内容进行扫描并转义,接收到的内容也要进行反转义。
一种解决策略是,发送方对需要发送的内容预先进行base64编码,由于base64编码只包含64个字符:0-9、a-z、A-Z、+、/,我们可以选择这64个字符之外的特殊字符作为分隔符。
DelimiterBasedFrameDecoder提供了多个构造方法,最终调用的都是以下构造方法:
参数说明:
LineBasedFrameDecoder可以当成是一种特殊的DelimiterBasedFrameDecoder,其分隔符为\n或者\r\n。
发送方的编码如下:
接收方的解码如下:
FixedLengthFrameDecoder是通过发送方固定每条报文长度均为n个字节,接收方也通过n个字节长度切分报文。
发送方需要自行补齐长度,编码如下:
接收方的解码如下:
缺点:如果发送的内容比较小,需要补齐长度,空间浪费,如果要发送的内容突然变大,需要调整发送方和接收方的长度。
LengthFieldBasedFrameDecoder的构造方法如下:
参数说明:
参考:
https://www.cnblogs.com/Leo_wl/p/10297113.html
https://www.cnblogs.com/sidesky/p/6913109.html
https://blog.csdn.net/u022812849/article/details/107254239
https://www.jianshu.com/p/c90ec659397c
https://network.51cto.com/art/201910/604438.htm