netty4.0源码解析(持续更新)

本文详细介绍了Netty的环境配置,包括Maven配置、JDK版本选择等,并探讨了Netty与其他框架的对比。接着,深入讲解了Netty的设计模式,如策略模式、责任链模式等,以及ByteBuf的内存管理和解码器的工作原理。此外,还涉及了protobuf的序列化机制和Netty中的编码解码器。最后,文章提到了一些常见问题,如断线重连、心跳保活机制等,并提供了相关解决方案。
摘要由CSDN通过智能技术生成

netty

1:环境配置

  1. 注释所有
   <!-- <module>all</module>-->
<!--    <module>resolver-dns-native-macos</module>-->

<!--    <module>transport-native-unix-common-tests</module>
    <module>transport-native-unix-common</module>
    <module>transport-native-epoll</module>
    <module>transport-native-kqueue</module>-->

  <!--  <module>testsuite</module>
    <module>testsuite-autobahn</module>
    <module>testsuite-http2</module>
    <module>testsuite-osgi</module>
    <module>testsuite-shading</module>
    <module>testsuite-native</module>
    <module>testsuite-native-image</module>
    <module>testsuite-native-image-client</module>
    <module>testsuite-native-image-client-runtime-init</module>
    <module>transport-blockhound-tests</module>-->

注释${tcnative.classifier}

更改maven jdk编译版本

<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>

2:跳过运行时error

3:关闭校验

checkstyle.xml

4:maven deprecation 错误

<!--   <showDeprecation>true</showDeprecation>-->
<!--    <module>microbench</module>-->

5: 修改jdk版本

<!-- JDK12 NEW -->
<profile>
  <id>java1.8</id>
  <activation>
    <jdk>16</jdk>
  </activation>
  <properties>
    <!-- Not use alpn agent as Java11+ supports alpn out of the box -->
    <argLine.alpnAgent />
    <argLine.java9.extras />
    <!-- Export some stuff which is used during our tests -->
    <argLine.java9>--illegal-access=deny ${argLine.java9.extras}</argLine.java9>
    <forbiddenapis.skip>true</forbiddenapis.skip>
    <!-- Needed because of https://issues.apache.org/jira/browse/MENFORCER-275 -->
    <enforcer.plugin.version>3.0.0-M3</enforcer.plugin.version>
    <!-- 1.4.x does not work in Java10+ -->
    <jboss.marshalling.version>2.0.5.Final</jboss.marshalling.version>
    <!-- This is the minimum supported by Java12+ -->
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <!-- pax-exam does not work on latest Java12 EA 22 build -->
    <skipOsgiTestsuite>true</skipOsgiTestsuite>
  </properties>
</profile>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YnxPakO9-1639712908078)(C:\Users\GIGA25\Desktop\学习\image-20210514225811386.png)]

6:程序包sun.misc不存在

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GCHXS96j-1639712908080)(C:\Users\GIGA25\Desktop\学习\image-20210514230131104.png)]

7:注释异常

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D8mQwDSz-1639712908081)(C:\Users\GIGA25\Desktop\学习\image-20210514230247691.png)]

与其他对比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8jcshz5k-1639712908082)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210518131114680.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zlrMMHqf-1639712908083)(C:\Users\GIGA25\Desktop\学习\image-20210518131124117.png)]

Callable call = 》 run Runnable

Future继承run作为callable桥接类

future缺陷

join:无法获取结果

future:获取结果线程需要阻塞

最终结果:通过Guava异步回调获取结果处理

2:结构

EventLoopGroup
EventLoop  Executor   ,Reactor,绑定一个线程和Selector
SocketChannel   :NioServerSocketChannel   channel  包含SelectableChannel
ChannelHandler
ChannelPipeline
ChannelFuture  :因为所有操作都是异步的,所以future返回结果
ChannelPipeline
ByteBuf            buffer

handler n-》1 pipeline 1-》1 Channel n - 》1 EventLoop n - 》 1 EventLoopGroup

EventLoop 1 -》 1 Thread

3:设计模式 delay

策略模式 todo

责任链模式 todo

单例模式模式 todo

装饰者模式

ReplayingDecoder todo

观察者模式 todo

迭代器模式 todo

工厂模式 todo

组合模式

CombinedChannelDuplexHandler

4:netty源码解析

Channel todo

Future todo

对Future增强,调用以非阻塞处理回调的结果

引入GenericFutureListener,表示异步执行完成的监听器。采用监听器模式,监听异步任务执行从而执行回调方法。

ChannelHandler todo

ChannelInboundHandler

ChannelInboundHandlerAdapterSimpleChannelInboundHandler类,在这里顺便说下它们两的区别吧。 继承SimpleChannelInboundHandler类之后,会在接收到数据后会自动release掉数据占用的Bytebuffer资源。并且继承该类需要指定数据格式。 而继承ChannelInboundHandlerAdapter则不会自动释放,需要手动调用ReferenceCountUtil.release()等方法进行释放。继承该类不需要指定数据格式。 所以在这里,个人推荐服务端继承ChannelInboundHandlerAdapter,手动进行释放,防止数据未处理完就自动释放了。而且服务端可能有多个客户端进行连接,并且每一个客户端请求的数据格式都不一致,这时便可以进行相应的处理。 客户端根据情况可以继承SimpleChannelInboundHandler类。好处是直接指定好传输的数据格式,就不需要再进行格式的转换了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BE7E1JVF-1639712908084)(C:\Users\GIGA25\Desktop\学习\image-20210513215652796.png)]

  • HttpRequestDecoder 即把 ByteBuf 解码到 HttpRequest 和 HttpContent。

  • HttpResponseEncoder 即把 HttpResponse 或 HttpContent 编码到 ByteBuf。

  • HttpServerCodec 即 HttpRequestDecoder 和 HttpResponseEncoder 的结合。

  • HttpObjectAggregator 即通过它可以把 HttpMessage 和 HttpContent 聚合成一个 FullHttpRequest 或者 FullHttpResponse (取决于是处理请求还是响应),而且它还可以帮助你在解码时忽略是否为“块”传输方式。
    
    因此,在解析 HTTP POST 请求时,请务必在 ChannelPipeline 中加上 HttpObjectAggregator。
    

handlerAdded:  ch.pipeline().addLast(inHandler); 触发
channelRegistered:通道注册完成后,成功绑定NioEventLoop线程后,会调用fireChannelRegistered,触发通道注册事件
channelActive:当通道激活完成后(所有的业务处理器添加,注册的异步任务完成,并且NioEventLoop线程绑定的异步任务完成),会调用fireChannelActive,触发通道激活事件
channelRead:当通道缓冲区可读,会调用fireChannelRead,触发通道可读事件
channelReadComplete:通道缓冲区读完,调用fireChannelReadComplete,触发通道读完事件

channelInactive:连接断开或不可用(当通道的底层连接已经不是ESTABLISH状态,或者底层连接已经关闭时),调用fireChannelInactive,触发连接不可用
exceptionCaught:抛出异常,调用fireExceptionCaught,触发异常捕获事件

handlerRemoved:netty移除通道上所有的业务处理器
释放buf

若继承ChannelInboundHandlerAdapter,

//手动释放
in.release();
//调用父类释放
super.channelRead(ctx,msg);  会调用末端TailHandler末尾处理器自动释放缓冲区

SimpleChannelInboundHandler释放

//手动释放
in.release();
实现channelRead0方法,使用自动释放

Decoder

ByteToMessageDecoder

解码器:为入站处理器

作用:将byteBuf解码成pojo,负责ByteBuf的释放.

实现方式:解码数据放入out集合后,父类不断循环遍历每个out元素执行后续handler.

ReplayingDecoder

第一个接收byte默认直接内存缓冲区.

使用ReplayingDecoder,该类装饰了buffer,在缓冲区真的读数据时,会判断长度是否够,不够异常.然后捕获,等下次IO事件到时读取.

作用:

  • 在读取ByteBuf缓冲区之前,检查缓冲区是否足够字节。

  • 整数的分包解码器。

//保存当前解码器在解码过程中的当前阶段,默认null
private S state;
读断点指针,当读数据时,一旦可读数据不够,则抛出异常之前,会将读指针还原之前checkPoint.下次读取从checkPoint读取
private int checkpoint = -1;

缺点:

  1. 不是所有byteBuf被ReplayingDecoder支持
  2. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QRlTft4V-1639712908085)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210527210647090.png)]
MessageToMessageDecoder

作用:将pojo转换另一种pojo,实参需要指定入站消息pojo类型

public class Integer2StringDecoder extends MessageToMessageDecoder<Integer> {
    @Override
    protected void decode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception {
        //子类执行完后,将遍历out所有元素.逐个发送给下站Inbound入站处理器
        out.add(String.valueOf(msg));
    }
}
其它decoder

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6nNqQBUp-1639712908086)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210527221907390.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sx3tlzPM-1639712908087)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210527221923194.png)]

LengthFieldBasedFrameDecoder

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vMGnmavK-1639712908087)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210529170102094.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TfRQKApN-1639712908088)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210529171245023.png)]

Encoder

MessageToByteEncoder

编码器:流水线从后向前执行。

作用:将pojo编码成byte

MessageToMessageEncoder

作用:将pojo编码成pojo,存入out,将遍历每个元素向前执行handler

编码解码器

ByteToMessageCodec

配套提供编码解码器

CombinedChannelDuplexHandler

通过组合方式,自定义编码解码器

ChannelOutboundHandler

bind:监听地址,完成底层io通道的ip地址绑定,若使用Tcp,则只能服务端用
connect:连接服务端,如果使用TCP传输协议,只作用客户端
disconnect:断开与服务端连接,如果使用TCP传输协议,只作用客户端
close:主动关闭通道
释放buf

HeadHandler释放

ChannelHandlerContext

表示ChannelHandler和ChannelPipeline 之间关联

作用

  1. 获取上下文所关联netty组件实例,如关联的通道,关联的流水线,上下文内部handler业务处理器实例等
  2. 入站和出站处理方法

和ChannelHandler和ChannelPipeline不同,如果用ChannelHandlerContext则只会从当前的节点开始执行Handler业务处理器,并传播到同类型处理器的下一节点.

ChannelPipeline todo

双向链表

支持热插拔:动态删除,增加流水线上处理器

addFirst(String name, ChannelHandler handler); 头部添加handler
addLast(String name, ChannelHandler handler); 尾部添加handler
addBefore(String baseName, String name, ChannelHandler handler); 在baseName处理器的前面添加handler
addAfter(String baseName, String name, ChannelHandler handler);在baseName处理器的后面添加handler

EventLoop

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-umrXsJ0M-1639712908088)(C:\Users\GIGA25\Desktop\学习\image-20210518231730078.png)]

ByteBuf

池化

​ 创建一个buf池,需要buf从池拿出,不需要则放回.然后通过引用计数方式来维护释放分配

计数=0则:

  1. Pooled池化Buf放入池中,等待下次分配
  2. 未池化buf,若是堆,则被jvm回收,若是直接内存类型,调用本地方法释放外部内存
UnpooledByteBufAllocator / PooledByteBufAllocator :采用jemalloc高效内存分配策略

读取和写入索引分开,目前javanio是flip/clean来切换读写模式,而netty不一样,通过维护2套读写索引

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dRennwFa-1639712908089)(C:\Users\GIGA25\Desktop\学习\image-20210520192227151.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9wAeaCBv-1639712908090)(C:\Users\GIGA25\Desktop\学习\image-20210520192701813.png)]

创建完一个buf,引用计数=1,为0表示buf没有任何进程引用,占用的内存需要回收
refCnt:获取引用次数
retain:引用次数+1,引用为0,在此引用抛出异常
release:释放引用次数-1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vOMGAn9L-1639712908091)(C:\Users\GIGA25\Desktop\学习\image-20210520225040444.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dEQMRw4O-1639712908091)(C:\Users\GIGA25\Desktop\学习\image-20210520225048609.png)]

浅层复制

slice():返回buf可读部分切片
slice(int index, int length):指定位置切片
duplicate():全部浅层复制.不会改变源引用计数.读写指针,最大容量与源一样.
存在问题,buf释放资源了,浅层复制的就不能读写了。可通过调用一次retain()增加引用.使用浅层buf后释放.

序列化

protobuf

// [开始声明]
syntax = "proto3";
//定义protobuf的包名称空间
package com.crazymakercircle.netty.protocol;
// [结束声明]

// [开始 java 选项配置]  在生成proto文件中消息的pojo类和builder(构造者)的java代码时,将java代码放入指定package
option java_package = "io.netty.example.chapter2.protocol";
option java_outer_classname = "MsgProtos"; //在生成proto文件所对应的java代码时,所生成的java外部类的名称.
// [结束 java 选项配置]

// [开始 消息定义]
//message定义消息结构体,对应javapojo类
message Msg {
  uint32 id = 1;  // Unique ID number for this person.  表示字段类型,字段名,排序位置
  string content = 2;
}

// [结束 消息定义]

文件启动

下载protoc3.6.1.exe

执行命令

./protoc3.6.1.exe ./Msg.proto --java_out=./

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5c1MAATA-1639712908091)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210529211845429.png)]

maven插件启动

<build>
    <plugins>
        <plugin>
            <groupId>org.xolstice.maven.plugins</groupId>
            <artifactId>protobuf-maven-plugin</artifactId>
            <version>0.5.0</version>
            <extensions>true</extensions>
            <configuration>
                <!--proto文件路径-->
                <protoSourceRoot>${project.basedir}/protobuf</protoSourceRoot>
                <!--目标路径-->
                <outputDirectory>${project.build.sourceDirectory}</outputDirectory>
                <!--设置是否在生成java文件之前清空outputDirectory的文件-->
                <clearOutputDirectory>false</clearOutputDirectory>
                <!--临时目录-->
                <temporaryProtoFileDirectory>${project.build.directory}/protoc-temp</temporaryProtoFileDirectory>
                <!--protoc 可执行文件路径-->
                <protocExecutable>${project.basedir}/protobuf/protoc3.6.1.exe</protocExecutable>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>


    </plugins>

</build>

执行compile命令执行

引入maven,

    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java</artifactId>
      <version>3.6.1</version>
    </dependency>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lxMV7Nu1-1639712908092)(C:\Users\GIGA25\Desktop\学习\image-20210529212415741.png)]

内置protobuf序列化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UPSnkyuK-1639712908092)(C:\Users\GIGA25\Desktop\学习\image-20210529220406559.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RinNFflg-1639712908093)(C:\Users\GIGA25\Desktop\学习\image-20210529220434560.png)]

protobuf语法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cdTBM1x0-1639712908093)(C:\Users\GIGA25\Desktop\学习\image-20210529222923160.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u0yAwYAl-1639712908094)(C:\Users\GIGA25\Desktop\学习\image-20210529222947566.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AulSvCaL-1639712908094)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210529224804141.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WLHxfZ32-1639712908095)(C:\Users\GIGA25\Desktop\学习\image-20210529224812222.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l0oBNyum-1639712908095)(C:\Users\GIGA25\Desktop\学习\image-20210529224826781.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ckEG8J3l-1639712908096)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210529230837562.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZPuxgeQO-1639712908096)(C:\Users\GIGA25\Desktop\学习\image-20210529224942036.png)]

5:常见问题 todo

如何实现断线重连

如何实现长连接心跳保活机制

如何解决epoll空轮训导致cpu100%的bug

对空闲线程心跳的处理

粘包&拆包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qli5dbHZ-1639712908096)(C:\Users\GIGA25\Desktop\学习\image-20210529184144792.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IDOtBNAu-1639712908097)(C:\Users\GIGA25\Desktop\学习\image-20210529184152981.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zc99j5H5-1639712908097)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210529184222240.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nSd5TokL-1639712908098)(C:\Users\GIGA25\AppData\Roaming\Typora\typora-user-images\image-20210529184242089.png)]

原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nuA6mH7f-1639712908098)(C:\Users\GIGA25\Desktop\学习\image-20210529185946057.png)]

解决方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8U3GzdlF-1639712908099)(C:\Users\GIGA25\Desktop\学习\image-20210529190040320.png)]

ByteBuf内存泄漏问题排查

6:内存模型 todo

AIO

NIO

BIO

mmap

zero-copy

7:线程模型 todo

Reactor

8:protobuf编解码机制 todo

9:Reactor响应式编程 todo

10:手写IM

1:指定协议

参考

https://netty.io/4.1/api/index.html netty-api

https://netty.io/wiki/related-articles.html

https://www.iocoder.cn/Netty/Netty-collection/

https://www.bianchengquan.com/article/597368.html

https://github.com/sanshengshui/netty-learning-example

https://www.cnblogs.com/sanshengshui/p/9774746.html

https://segmentfault.com/a/1190000007282789

https://mp.weixin.qq.com/s?__biz=MzIxMDAwMDAxMw==&mid=2650725011&idx=1&sn=741b290093788f820cbb61905cc214bb&chksm=8f613b71b816b26775629757c9aec632ce645f8cdee5848e056300b09f1874a28205ed54151b&mpshare=1&scene=23&srcid=&sharer_sharetime=1570838084571&sharer_shareid=12ae0c9c538778cd36ca6e4500b81b6f#rd

​ github https://github.com/fuzhengwei/itstack-demo-netty

Netty实战 <人邮><工信>

Java高并发核心编程 卷1:NIO、Netty、Redis、ZooKeeper <机械工业出版社]>

​ github:https://gitee.com/crazymaker/crazy_tourist_circle__im

Netty权威指南 <李林峰> <电子工业出版社>

Netty进阶之路跟着案例学Netty 李林锋 <电子工业出版社>

Netty 4核心原理与手写RPC框架实战 <电子工业出版社>

​ github https://github.com/gupaoedu-tom/netty4-samples

Netty原理解析与开发实战

Netty4开发手册

Netty手册

Netty5.0架构剖析和源码解读

https://www.52doc.com/download/7341 下载所有电子书

**《 Java 高并发 三部曲 》****

https://www.cnblogs.com/crazymakercircle/p/9904544.html

理论场景实践

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值