ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Netty学习(三)

2021-04-04 16:33:03  阅读:158  来源: 互联网

标签:Netty 解码 粘包 学习 解码器 数据 out


Netty

Google Protobuf

  • 编码和解码

    • 编写网络应用程序时,因为数据在网络中传输的都是二进制字节码数据,在发送数据时就需要编码,接收数据时就需要解码。
    • codec(编解码器)的组成部分有两个:decoder(解码器)和coder(编码器)。encoder负责把业务数据转换成字节码数据;decoder负责把字节码数据转换为业务数据
  • Netty本身的编解码机制和问题分析

    • netty自身提供了一些cedec(编解码器)
    • netty提供了StringEncoderStringDecoder,可以对字符串数据进行编解码;ObjectEncoderObjectDecoder可以对java对象进行编解码
    • Netty本身自带的ObjectEncoderObjectDecoder可以用来实现POJO对象或各种业务对象的编码和解码,底层使用的仍然是java序列化技术,效率不高,存在以下问题:
      • 无法跨语言
      • 序列化后的体积太大,是二进制代码的五倍多
      • 序列化性能太低

在这里插入图片描述

  • Protobuf
    • Protobuf是Google的开源项目,是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化。很适合用于做数据存储或RPC(远程过程调用)数据交换格式。——http + jsontcp + protobuf
    • Protobuf是以message的方法是来管理数据的。使用protobuf的编译器能够自动生成代码,是将类的定义.proto文件进行描述,然后通过proto.exe编译器自动生成.java文件。
Student.proto

syntax = "proto3"; //版本
option java_outer_classname = "StudentPOJO";//生成的外部类名,同时也是文件名
//protobuf 使用message 管理数据
message Student { //会在 StudentPOJO 外部类生成一个内部类 Student, 他是真正发送的POJO对象
    int32 id = 1; // Student 类中有 一个属性 名字为 id 类型为int32(protobuf类型) 1表示属性序号,不是值
    string name = 2;
}

//编译
//protoc.exe--java_out=.Student.proto
//将生成的 StudentPOJO 放入到项目使用

Netty编解码器和Handler调用机制

  • 基本说明

    • Netty的组件设计有:Channel、EventLoop、ChannelFuture、ChannelHandler、ChannelPipeline等
    • ChannelHandler充当了入站和出站数据的应用程序逻辑的容器。例如实现ChannelInboundHandler接口(或者ChannelInboundHnadlerAdapter接口),可以接收入站事件和数据。这些数据会被业务逻辑处理。当要给客户端发送响应时,可以从ChannelIndoundHandler冲刷数据。业务逻辑通常写在一个或者多个ChannelInboundHandler中。ChannelOutboundHandler原理类似,只不过是用来处理出站数据的
    • ChannelPipeline提供了ChannelHandler链的容器。当事件是从Channel中进入端程序时,称事件为入站的;当事件是从端程序进入Channel中,称为出站的事件。
  • 编码解码器

    • 当Netty发送或者接受一个消息的时候,就将会发生一次数据转换。入站消息会被解码,从字节转换为另一种格式,如果是出站消息,会被编码成字节。
    • Netty提供一系列使用的编解码器,他们都实现了ChannelInboundHandler或者ChannelOutboundHandler接口。在这些类中,channelRead()方法已经被重写了。入站时,对每个从入站Channel读取的信息,这个方法会被调用。随后,他将调用解码器提供的decode()方法进行解码,并将已经解码的字节转发给pipeline中的下一个InboundHandler。
  • 解码器 - ByteToMessageDecoder

    • 由于不可能知道远程节点是否会一次性发送一个完整的信息,tcp有可能会出现粘包拆包的问题,这个类会对入站数据进行缓冲,直到他准备好被处理。
public class ToIntegerDecoder extends ByteToMessageDecoder{
	@Override
	protected void decode(ChannelHandlerContext ctx , ByteBuf in , List<Object> out) throws Exception{
		if (in.readableBytes() >= 4){
			out.add(in.readInt());
		}
	}
}
//在每次入站从ByteBuf中读取4字节,并将其解码为一个int,然后将其添加到一个list中。该方法会被反复调用,直到没有更多元素被添加到list集合中(即ByteBuf读取结束)时,该List的内容会被发送给下一个ChannelInboundHandler.
  • Netty的handler链的调用机制
    以客户端服务器之间传送Long型数据为例,在客户端向服务器发送Long型数据时,需要在客户端channel的pipeline中添加编码器和业务处理器;在服务器端channel的pipeline中添加解码器和业务处理器。需要注意的是,解码器和编码器都需要在业务处理器之前定义到pipeline中。

    • 不论解码器handler还是编码器handler,接受的消息类型必须各待处理的消息类型一致,否则该handler不会被执行。
    • 在编码器进行数据解码时,需要判断缓存区(ByteBuf)的数据是否足够,否则接收到的结果会和期望结果不一致。
  • 解码器 - ReplayingDecoder
    该解码器继承了ByteToMessageDecoder:publci abstract class ReplayingDecoder <S> extends ByteToMessageDecoder

    • ReplayingDecoder扩展了ByteToMessageDecoder类,只用这个类不需要调用readableBytes()方法,参数S指定了用户状态管理的类型,其中Void表示不需要状态管理
    • ReplayingDecoder使用起来较为方便,但是也具有一定的局限性
      • 并不是所有的ByteBuf操作都被支持,如果调用了一个不被支持的方法,将会抛出一个UnsupportedOperationException
      • RepalyingDecoder在一些情况下可能会稍慢与ByteToMessageDecoder,如网络消息缓慢且消息格式复杂时,消息会被拆成多个碎片,速度变慢。
public class MyDecoder extends ReplayingDecoder<Void> {
	@Override
	protected void decode(ChannelHandlerContext context , ByteBuf byteBuf , List<Object> out) throws Exception{
		System.out.println("解码器被调用...");
		//ReplayingDecoder在使用时不需要判断数据是否足够读取
		//if(byteBuf.readableBytes() >= 8){
		//	out.add(byteBuf.readLong());
		//}
		out.add(byteBuf.readLong());
	}
}

  • 其他解码器
    • LineBasedFrameDecoder:这个类在 Netty 内部也有使用,它使用行尾控制字符(\n或者\r\n)作为分隔符来解析数据。
    • DelimiterBasedFrameDecoder:使用自定义的特殊字符作为消息的分隔符。
    • HttpObjectDecoder:一个 HTTP 数据的解码器
    • LengthFieldBasedFrameDecoder:通过指定长度来标识整包消息,这样就可以自动的处理黏包和半包消息。

TCP粘包和拆包及解决方案

在这里插入图片描述

  • TCP粘包拆包基本介绍

    • TCP是面向连接,面向流的,提供高可靠性服务。收发两端都要有一一成对的socket。因此发送端为了将多个发给接收端的包更有效的发给对方,使用了优化方法,将多次间隔较小且数据量小的数据,合并成一个大的数据块然后进行封包。这样做虽然提高了效率,但是接收端就比较难以分辨出完整的数据包了,因为面向流的通信是无消息保护边界的。
    • 由于TCP无消息保护边界,需要在接收端处理消息边界问题,也就是粘包拆包问题。
    • 上图的四种情况即为通信过程中可能出现粘包拆包问题的情况。
  • TCP粘包拆包问题解决方案

    • 使用自定义协议+编解码器来解决
    • 关键是要解决服务器端每次读取数据长度的问题,这个问题解决,就不会出现服务器多读或者少读数据的问题,从而避免TCP拆包、粘包。

Netty核心源码剖析

使用Netty实现Dubbo RPC

标签:Netty,解码,粘包,学习,解码器,数据,out
来源: https://blog.csdn.net/WOD_MAAYA/article/details/115427344

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有