Netty学习09-粘包和分包及FrameDecoder源码解析

粘包出现的原因:服务端与客户端没有约定好要使用的数据结构。Socket Client实际是将数据包发送到一个缓存buffer中,通过buffer刷到数据链路层。因服务端接收数据包时,不能断定数据包1何时结束,就有可能出现数据包2的部分数据结合数据包1发送出去,导致服务器读取数据包1时包含了数据包2的数据。这种现象称为粘包。
分包:数据包数据被分开一部分发送出去,服务端一次读取数据时可能读取到完整数据包的一部分,剩余部分被第二次读取。

解决办法一般是通过定义一个稳定的结构,比如一个完整的消息包数据结构为:包头+数据包长度+数据包。

服务器有的通过重写FrameDecoder的decode方法来处理粘包与分包;代码示例如下:
 

public class MyDecoder extends FrameDecoder {

	@Override
	protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {

		if(buffer.readableBytes() > 4){
			
			if(buffer.readableBytes() > 2048){
				buffer.skipBytes(buffer.readableBytes());
			}
			
			
			//标记
			buffer.markReaderIndex();
			//长度
			int length = buffer.readInt();
			
			if(buffer.readableBytes() < length){
				buffer.resetReaderIndex();
				//缓存当前剩余的buffer数据,等待剩下数据包到来
				return null;
			}
			
			//读数据
			byte[] bytes = new byte[length];
			buffer.readBytes(bytes);
			//往下传递对象
			return new String(bytes);
		}
		//缓存当前剩余的buffer数据,等待剩下数据包到来
		return null;
	}

}

 

然后再设置管道属性的时候,添加如下代码即可。

大家难免会有疑惑,decode处理的数据如何传递给下一个处理类;另外,decode处理类返回null之后会怎么样。我们通过这样一个场景(第一次来的包数量不够,不足以解析,第二次才能解析)来分析源码。当然了,这种情况支持,没有粘包和分包的正常情况也是支持的。

下面我们一起看下FrameDecoder的源码,,通过上一篇文章大家可以知道,既然这个类继承于SimpleChannelUpstreamHandler,那么消息来了之后首先会调用他的messageReceived方法,源码如下:

当第一次进来之后,由于cumulation是空的,所以会直接调用callDecode方法

通过这段代码,我们可以知道,首先会判断cumulation,也就是上面方法传入的input里面是不是有数据可以读取,如果有的话会先记录原始的读取位置,然后调用我们重写的decoder,如果返回的是null,并且现在的读取位置和原始的一致,那么认为没有办法完成读取,所以直接break跳出循环,然后返回到调用方之后,直接执行finally方法。

该方法是将数据更新到cumulation中。

待下次再来处理数据的时候,由于cumulation中已经有了数据,会进行追加,然后调用callDecode方法,此时会执行如下方法

查看该方法源码:

发现会调用fireMessageReceived方法,该方法源码如下:

至此,通过上一篇文章我们知道,这个方法是循环取出handler执行,所以也就明白了Decoder的decode为什么能把消息传递给别的处理类了。

除此之外,上面的callDecode里面是个while循环,也就是说如果里面有多个消息包,也是可以处理的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值