Netty源码分析

转载自:https://blog.csdn.net/charjay_lin/article/details/82726400

 

1.Promise 与 Future

https://www.jianshu.com/p/c9a7947fe736

https://www.cnblogs.com/ironroot/p/8583045.html

2.Handler的各种姿势

2.1.ChannelHandlerContext

每个ChannelHandler被添加到ChannelPipeline后,都会创建一个ChannelHandlerContext并
与之创建的ChannelHandler关联绑定。ChannelHandlerContext允许Channelllandler与其他的
ChannelHandler实现进行交互。ChannelHandlerContext不会改变添加到其中的ChannelHandler,因此它是安全的。
下图显示了ChannelHandlerContext、ChannelHandler、ChannelPipeline的关系:

2.2.Channel的状态模型

Netty有一个简单但强大的状态横型,并完美映射到ChannelInboundHandler的各个方法。下面
是Channel生命周期四个不同的状态:
1.channelUnregistered
2.channe1Registered
3.channelActive
Channel的状态在其生命周期中变化,因为状态变化需要触发,下面显示了Channel状态变化

image.png | left | 551x273

2.3.ChannelHandler和其他子类

Handler的类继承图

image.png | left | 608x326

2.4.ChannelHandler中的方法

Netty 定义了良好的类型层次结构来表示不同的处理程序类型,所有的类型的父类是 Channe1Handler 。 Channe1Handler提供了在其生命周期内添加或从 ChannelPipeline 中删除的方法。
1 . handlerAdded , Channe1Handler添加实际上下文中准备处理事件
2 . handlerRemoved ,将 Channe1Handler 从实际上下文中删除,不再处理事件
3 . exceptionCaught ,处理抛出的异常

Netty 还提供了一个实现了 Channe1Handler 的抽象类 Channe1HandlerAdapter 。 Channe1HandlerAdapter 实现了父类的所有方法,基本上就是传递事件到 ChannelPipeline 中的下一个 Channe1Handler直到结束。我们也可以直接继承于Channe1HandlerAdapter,然后重写里面的方法。

 

2.5.ChannelInboundHandler

ChannelInboundHandler 提供了一些方法再接收数据或Channel状态改变时被调用。下面是ChannelInboundHandler 的一些方法:

1.channelRegistered,ChannelHandlerContext的Channel被注册到 EventLoop;
2.channelUnregistered,ChannelHandlerContext 的Channel从EventLoop中注销
3.channelActive,ChannelHandlerContext 的Channel 已激活
4.channelInactive,ChannelHandlerContext 的 Channel 结束生命周期
5.channelRead,从当前Channel的对端读取消息
6.0hanne1ReadComplete,消息读取完成后执行
7.userEventTriggered,一个用户事件被触发
8.channelWritabilityChanged,改变通道的可写状态,可以使用Channel.isWritable()检查
9.exceptionCaught,重写父类ChannelHandler的方法,处理异常

Netty提供了一个实现了ChannelInboundHandler接口并继承ChannelHandlerAdapter的类:
ChannelInboundHandlerAdapter 。ChannelInboundHandlerAdapter实现了
ChannelInboundHandler的所有方法,作用就是处理消息并将消息转发到ChannelPipeline中的
下一个,ChannelHandler。ChannelInboundHandlerAdapter的channelRead方法处理完消息后不
会自动释放消息,若想自动释放收到的消息,可以使用SimpleChannelInboundHandler。

3.编码和解码

3.1.TCP粘包/拆包

TCP是一个“流”协议,所谓流,就是没有界限的一长串二进制数据。TCP作为传输层协议并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行数据包的划分,所以在业
务上认为是一个完整的包,可能会被TCP拆分成多个包进行发送,也有可能把多个小的包到装成
一个大的数据包发这,这就是所谓的TCP粘包和拆包问题

3.2.粘包问题的解决策略

由于底层的TCP无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这
个问题只能通过上层的应用协议栈设计来解决。业界的主流协议的解决方案,可以归纳如下:

1.消息定长,报文大小固定长度,例如毎个报文的长度固定为200字节,如果不够空位补空格;
2.包尾添加特殊分隔符,例如毎条报文结朿都添加回车换行符(例如FTP协议)或者指定特殊
字符作为报文分隔符,接收方通过特殊分隔符切分报文区分;
3.将消息分为消息头和消息体,消息头中包含表示信患的总长度(或者消息体长度)的字段;
4.更复杂的自定义应用层协议。

3.3.编码解码技术

通常我们也习惯将編码(Encode〉称为序列化(serialization),它将对象序列化为字节数组,
用于网络传输.数据持久化或者其它用途。
反之,解码(Decode)/反序列化(deserialization)把从网络、磁盘等读取的字节数组还原成
原始对象(通常是原j始对象的烤贝),以方便后续的业务逻辑操作。
逬行远程跨逬程服务调用时(例如狀(:调用),需要使用特定的编解码技术.对需要逬行网络传
输的对象做編码或者解码,以便完成远程调用。

3.4.Netty为什么要提供编解码框架

作为一个高性能的异步、NI0通信框架,編解码框架是Netty的重要组成部分。尽管站在微内核
的角度看,编解码框架丼不是Netty微内核的组成部分,但是通过Channelllandler定制扩展出的編解码框架却是不可或缺的。

然而,我们已经知道在Netty中,从网络读取的Inbound消息.需.要经过解码,将二进制的数据
报转換成应用层协议消息或者业务消息,才能够被上层的应用逻辑识别和处理:同理,用户发送
到网络的Outbound业务消息,索要经过编码转换成二进制字节数组(对于Netty就是ByteBuf)
才能够发送到网络对端。編码和解码功能是NIO框架的有机租成部分,无论是由业务定制扩展实
现,还是NIO框茉内I编解码能力,该功能是必不可少的。

为了降低用户的开发难度,Netty对常用的功能和API做了装饰,以屏蔽底层的实现细节。编解
码功能的定制,对于熟悉Netty底层实现的开发者而言,直接基于ChannelHandler扩展开发,
难度并不是很大,但是对于大多数初学者或不愿意去了解底层实现细节的用户.需要提供给他
们更简单的类库和API,而不是ChannelHandler
Netty在这方面做得非常出色,针对編解码功能,它既提供了通用的編解码框架供用户扩展,又
提供了常用的编解码类库供用户直接使用。在保证定制扩展性的基础之上,尽景降低用户的开发
工作量和开发门槛,提升开发效率。Netty预置的编解码功能列表如下:base64、Protobuf、spdy等。

image.png | left | 148x246

3.5.Netty粘包和拆包解决方案

3.5.1.Netty中常用的解码器 链接

Netty提供了多个解码器,可以进行分包的操作,分别是:
* LineBasedFrameDecoder
* DelimiterBasedFrameDecoder(添加特殊分隔符报文来分包)
* FixedLengthFrameDecoder(使用定长的报文来分包)
* LengthFieldBasedFrameDecoder

LineBasedFrameDecoder解码器

LineBasedFrameDecoder是回车换行解码器,如果用户发送的消息以回车换行符作为消息结束的标识,则可以直接使用Netty的LineBasedFrameDecoder对消息进行解码,只需要在初始化Netty服务端或者客户端时将LineBasedFrameDecoder正确的添加到ChannelPipeline中即可,不需要自己重新实现一套换行解码器。

DelimiterBasedFrameDecoder解码器

DelimiterBasedFrameDecoder是分隔符解码器,用户可以指定消息结束的分隔符,它可以自动完成以分隔符作为码流结束标识的消息的解码。回车换行解码器实际上是一种特殊的DelimiterBasedFrameDecoder解码器。

FixedLengthFrameDecoder解码器

FixedLengthFrameDecoder是固定长度解码器,它能够按照指定的长度对消息进行自动解码,开发者不需要考虑TCP的粘包/拆包等问题,非常实用。
对于定长消息,如果消息实际长度小于定长,则往往会进行补位操作,它在一定程度上导致了空间和资源的浪费。但是它的优点也是非常明显的,编解码比较简单,因此在实际项目中仍然有一定的应用场景。

LengthFieldBasedFrameDecoder解码器

大多数的协议(私有或者公有),协议头中会携带长度字段,用于标识消息体或者整包消息的长度,例如SMPP、HTTP协议等。由于基于长度解码需求的通用性,以及为了降低用户的协议开发难度,Netty提供了LengthFieldBasedFrameDecoder,自动屏蔽TCP底层的拆包和粘包问题,只需要传入正确的参数,即可轻松解决“读半包“问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty5.0 架构剖析和码解读 作者:李林锋 版权所有 email neu_lilinfeng@ © Netty5.0 架构剖析和码解读1 1. 概述2 1.1. JAVA 的IO演进2 1.1.1. 传统BIO通信的弊端2 1.1.2. Linux 的网络IO模型简介4 1.1.3. IO复用技术介绍7 1.1.4. JAVA的异步IO8 1.1.5. 业界主流的NIO框架介绍10 2.NIO入门10 2.1. NIO服务端10 2.2. NIO客户端13 3.Netty分析16 3.1. 服务端创建16 3.1.1. 服务端启动辅助类ServerBootstrap16 3.1.2. NioServerSocketChannel 的注册21 3.1.3. 新的客户端接入25 3.2. 客户端创建28 3.2.1. 客户端连接辅助类Bootstrap28 3.2.2. 服务端返回ACK应答,客户端连接成功32 3.3. 读操作33 3.3.1. 异步读取消息33 3.4. 写操作39 3.4.1. 异步消息发送39 3.4.2. Flush操作42 4.Netty架构50 4.1. 逻辑架构50 5. 附录51 5.1. 作者简介51 5.2. 使用声明51 1. 概述 1.1.JAVA 的IO演进 1.1.1. 传统BIO通信的弊端 在JDK 1.4推出JAVANIO1.0之前,基于JAVA 的所有Socket通信都采用 BIO 了同步阻塞模式( ),这种一请求一应答的通信模型简化了上层的应用开发, 但是在可靠性和性能方面存在巨大的弊端。所以,在很长一段时间,大型的应 C C++ 用服务器都采用 或者 开发。当并发访问量增大、响应时间延迟变大后, 采用JAVABIO作为服务端的软件只有通过硬件不断的扩容来满足访问量的激 增,它大大增加了企业的成本,随着集群的膨胀,系统的可维护性也面临巨大 的挑战,解决这个问题已经刻不容缓。 首先,我们通过下面这幅图来看下采用BIO 的服务端通信模型:采用BIO 通信模型的 1connect NewThread1 WebBrowse 2connect 2handle(Req) WebBrowse 3connect Acceptor NewThread2 WebBrowse WebBrowse 4connect NewThread3 3sendResponsetopeer NewThread4 图1.1.1-1 BIO通信模型图 服务端,通常由一个独立的Accepto 线程负责监听客户端的连接,接收到客户 端连接之后为客户端连接创建一个新的线程处理请求消息

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值