Netty学习(三)

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值