Netty(三) 什么是 TCP 拆、粘包?如何解决?(中)

简介: 记得前段时间我们生产上的一个网关出现了故障。 这个网关逻辑非常简单,就是接收客户端的请求然后解析报文最后发送短信。 但这个请求并不是常见的 HTTP ,而是利用 Netty 自定义的协议。 有个前提是:网关是需要读取一段完整的报文才能进行后面的逻辑。

服务端直接打印即可:


@Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        LOGGER.info("收到msg={}", msg);
    }


顺便提一下,这里加的有一个字符串的解码器:.addLast(new StringDecoder()) 其实就是把消息解析为字符串。


@Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
        out.add(msg.toString(charset));
    }


在 Swagger 中调用了客户端的接口用于给服务端发送了 100 次消息:



正常情况下接收端应该打印 100 次 hello 才对,但是查看日志会发现:



收到的内容有完整的、多的、少的、拼接的;这也就对应了上面提到的拆包、粘包。


该怎么解决呢?这便可采用之前提到的 LineBasedFrameDecoder 利用换行符解决。


利用 LineBasedFrameDecoder 解决问题


LineBasedFrameDecoder 解码器使用非常简单,只需要在 pipline 链条上添加即可。


//字符串解析,换行防拆包
.addLast(new LineBasedFrameDecoder(1024))
.addLast(new StringDecoder())


构造函数中传入了 1024 是指报的长度最大不超过这个值,具体可以看下文的源码分析。


然后我们再进行一次测试看看结果:


注意,由于 LineBasedFrameDecoder 解码器是通过换行符来判断的,所以在发送时,一条完整的消息需要加上 \n



最终的结果:



仔细观察日志,发现确实没有一条被拆、粘包。

LineBasedFrameDecoder 的原理


目的达到了,来看看它的实现原理:



  1. 第一步主要就是 findEndOfLine 方法去找到当前报文中是否存在分隔符,存在就会返回分隔符所在的位置。


  1. 判断是否需要丢弃,默认为 false ,第一次走这个逻辑(下文会判断是否需要改为 true)。


  1. 如果报文中存在换行符,就会将数据截取到那个位置。


  1. 如果不存在换行符(有可能是拆包、粘包),就看当前报文的长度是否大于预设的长度。大于则需要缓存这个报文长度,并将 discarding 设为 true。


  1. 如果是需要丢弃时,判断是否找到了换行符,存在则需要丢弃掉之前记录的长度然后截取数据。


  1. 如果没有找到换行符,则将之前缓存的报文长度进行累加,用于下次抛弃。


从这个逻辑中可以看出就是寻找报文中是否包含换行符,并进行相应的截取。


由于是通过缓冲区读取的,所以即使这次没有换行符的数据,只要下一次的报文存在换行符,上一轮的数据也不会丢。


高效的编码方式 Google Protocol


上面提到的其实就是在解码中进行操作,我们也可以自定义自己的拆、粘包工具。


编解码的主要目的就是为了可以编码成字节流用于在网络中传输、持久化存储。


Java 中也可以实现 Serializable 接口来实现序列化,但由于它性能等原因在一些 RPC 调用中用的很少。


Google Protocol 则是一个高效的序列化框架,下面来演示在 Netty 中如何使用。


相关文章
|
3月前
|
网络协议 Java Maven
基于Netty实现TCP通信
基于Netty实现TCP通信
64 0
|
5天前
|
编解码 网络协议 开发者
Netty运行原理问题之NettyTCP的粘包和拆包的问题如何解决
Netty运行原理问题之NettyTCP的粘包和拆包的问题如何解决
|
19天前
|
移动开发 网络协议 算法
(十)Netty进阶篇:漫谈网络粘包、半包问题、解码器与长连接、心跳机制实战
在前面关于《Netty入门篇》的文章中,咱们已经初步对Netty这个著名的网络框架有了认知,本章的目的则是承接上文,再对Netty中的一些进阶知识进行阐述,毕竟前面的内容中,仅阐述了一些Netty的核心组件,想要真正掌握Netty框架,对于它我们应该具备更为全面的认知。
|
3月前
|
网络协议
Netty实现TCP通信
Netty实现TCP通信
72 0
|
2月前
|
网络协议
netty粘包问题分析
netty粘包问题分析
20 0
|
2月前
|
消息中间件 存储 网络协议
拼多多面试:Netty如何解决粘包问题?
粘包和拆包问题也叫做粘包和半包问题,**它是指在数据传输时,接收方未能正常读取到一条完整数据的情况(只读取了部分数据,或多读取到了另一条数据的情况)就叫做粘包或拆包问题。** 从严格意义上来说,粘包问题和拆包问题属于两个不同的问题,接下来我们分别来看。 ## 1.粘包问题 粘包问题是指在网络通信中,发送方连续发送的多个小数据包被接收方一次性接收的现象。这可能是因为底层传输层协议(如 TCP)会将多个小数据包合并成一个大的数据块进行传输,导致接收方在接收数据时一次性接收了多个数据包,造成粘连。 例如以下案例,正常情况下客户端发送了两条消息,分别为“ABC”和“DEF”,那么接收端也应该收到两
19 0
拼多多面试:Netty如何解决粘包问题?
|
2月前
|
Java
Netty传输object并解决粘包拆包问题
Netty传输object并解决粘包拆包问题
20 0
|
2月前
|
Java
Netty中粘包拆包问题解决探讨
Netty中粘包拆包问题解决探讨
12 0
|
3月前
|
网络协议 Java 物联网
Spring Boot与Netty打造TCP服务端(解决粘包问题)
Spring Boot与Netty打造TCP服务端(解决粘包问题)
419 1
|
3月前
|
JSON 移动开发 网络协议
数据拆散与黏连:深入剖析Netty中的半包与粘包问题
数据拆散与黏连:深入剖析Netty中的半包与粘包问题
66 0