netty编解码,粘包拆包,心跳,重连
2022-02-23 19:34:12 0 举报
AI智能生成
netty编解码,粘包拆包,心跳,重连
作者其他创作
大纲/内容
编解码
编码器encoder是一个ChannelOutboundHandler, 用于拦截处理出站数据,将消息对象序列号成字节数组ByteBuf
解码器decoder是一个ChannelInboundHandler, 用于拦截处理入站数据,将字节数组ByteBuf反序列化成消息对象转成消息对象
解码器
ByteToMessageDecoder
响应channelRead事件
累积器:会先将butebuf放到累积器中,如果读到的包不是完整的,需要先将bytebuf放到累积器中,再到channel中读取新的包
累积器也是一个bytebuf,有merge和composite2种实现,前者是默认实现,会拷贝内存,后者是逻辑组合,内存消耗相对较少,但索引到具体某个bytebuf更耗时
实现类需要判断读到的包是否是完整的,如果不是则不做任何处理(不移动readerIndex, 不往out里面添加对象),上层调用者会继续从通道中读取数据包
ReplayingDecoder
和ByteToMessageDecoder的区别是,ReplayingDecoder在处理数据时可以认为所有的数据(ByteBuf) 已经接收完毕,而不用判断接收数据的长度
,使用更简单
,使用更简单
通过一个ByteBuf的包装类ReplayingDecoderByteBuf来实现,拦截了readXX方法,在读取之前先记录readerIndex,再判断可读长度是否足够,如果不够抛出一个Error, 重置readerIndex,并从通道中读取数据包
Error对象在常量池缓存起来了,避免重复创建
网络比较差,总是读不到一个完整的包时,它的decode方法会反复调用,如果里面实现了复杂的解析操作的话会影响性能
用状态保存解析到哪一步了,并把之前解析过的结果先暂存起来,避免重复解析影响性能
解码器职责:反序列化、处理粘包拆包,而编码器只需要序列化,实现更为简单
粘包拆包
tcp是面向流的协议,传输的最小单位是字节,当一次性发送多个数据包时,tcp将多个包打包成一个tcp报文发送出去,使接收方一次性收到了多个数据包,就是粘包;当发送的数据包超过最大报文大小时,tcp将它分成多个最大的tcp报文传输,使得接收方每次收到的数据包不是一个完整的包,就是拆包
解决方法
消息定长
传输的数据长度固定,不够用空格补齐,空格浪费带宽
数据包的末尾添加分隔符
比如http协议用\r\n分割,需要解析包体,性能较差
DelimiterBasedFrameDecoder,自定义分隔符
LineBasedFrameDecoder,行分隔
发送长度
在包的内部带上数据包的长度,解析时先读取长度,再根据长度读取消息体
LengthFieldBasedFrameDecoder
数据包由[魔数][消息头][长度域][消息头][消息体]构成,魔数和消息头是可选的,长度域和消息头位置可以互换,长度域的值可以表示消息体的大小,也可以表示整个包体的大小,解析后的包体只能是原包或者原包前面截取一部分
lengthFieldOffset
lengthFieldLength,这2个值用来定位长度域在包中的位置,从而取出长度域的值
lengthFieldLength,这2个值用来定位长度域在包中的位置,从而取出长度域的值
解码过程大体分为2步:
1、整个包体的长度=长度域的值+lengthFieldOffset + lengthFieldLength(长度域的结束漂移量)+lengthAdjustment
2、最终包体=initialBytesToStrip(开始截断的位置) 到 整个包体的长度-initialBytesToStrip
1、整个包体的长度=长度域的值+lengthFieldOffset + lengthFieldLength(长度域的结束漂移量)+lengthAdjustment
2、最终包体=initialBytesToStrip(开始截断的位置) 到 整个包体的长度-initialBytesToStrip
如果长度域的值表示的是消息体的大小,lengthAdjustment应该=0
如果长度域的值是消息大小,且消息头在长度域之后,lengthAdjustment应该等于消息头大小
如果长度域的值是整个包体的大小,lengthAdjustment应该等于(-长度域的结束漂移量)
如果长度域的值是消息大小,且消息头在长度域之后,lengthAdjustment应该等于消息头大小
如果长度域的值是整个包体的大小,lengthAdjustment应该等于(-长度域的结束漂移量)
再根据initialBytesToStrip截断即可
心跳检测
IdleStateHandler,通过这个channelHandler实现心跳检测,它是一个ChannelDuplexHandler,同时响应出站和入站事件
参数:读空闲时间、写空闲时间、所有空闲时间,如果配置了大于0,会使用eventLoop线程执行一个延时任务,检查上一次读写时间距离当前是否超过允许的空闲时间,如果超过,则触发读写空闲事件IdleStateEvent,后继channelhander的userEventTriggered会接收到
延时任务的延时时间的计算:如果正在读,则为允许的读写空闲时间;否则,等于读写空闲时间-上一次读写距离当前的时间,为了读之后允许的空闲时间后检查一次
0 条评论
下一页