教你玩转通信框架Netty🔥🔥

1,002 阅读7分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

相信大家对于Netty这个框架都耳熟能详,那么大家对于Netty的设计原则,对于Netty的用法是否熟悉呢?是否能够借助Netty实现心跳检测,网络服务器,RPC通信协议...本篇文章就我个人对于Netty的理解,进行一下分享,欢迎大家批评指正。

前言

去年的时候,我通过看一些教学视频、文章,对Netty这个框架进行了解,虽然也做了一些Demo,但是仍然感觉不知道如何去运用这个框架,最近阅读了不少框架的源码,在很多框架中都发现其通信模块都是基于Netty实现的,也加深了我对Netty运用的理解。

Netty最核心的能力是对NIO网络通信的封装与优化,其中封装了许多复杂的网络IO处理、多线程模型,由于其强大的影响力,许多公司,优秀的开发者都对其贡献了代码,使其通信功能越来越完备。

Netty 应用实例源码gitee.com/zhuhuijie/n…

网络编程

我们大家应该都熟悉OSI七层网络模型和TCP/IP五层模型,OSI七层网络模型是定义的标准,但是一直都没能很好的落实,普遍落实的标准一般都是TCP/IP五层模型,如下图所示(Netty的目的就简化我们从传输层到应用层网络方面的开发)。

image.png

网络传输都是屏蔽在传输层的,传输层以下是依赖于硬件网络(网卡、网线、路由器等等)进行传输的,所以从程序员的角度一般是不考虑传输层以下的编程的,我们一般都是对应用层协议进行定制,传输层一般都是使用TCP协议或者UDP协议进行可靠或不可靠传输。

传输层协议:

  • TCP协议: TCP(传输控制协议)是面向连接的协议,在收发数据前,必须和对方建立可靠的连接。
  • UDP协议: UDP (用户数据报协议)是一种无连接的传输层协议,提供面向事务的简单的不可靠的信息传送服务。

网络编程的本质就是跨进程的通信,通过网络IO,完成跨进程的数据交换,网络IO主要有以下几种模型。

网络IO模型:

  • BIO 同步阻塞IO, 一个线程处理一个连接
  • NIO 同步非阻塞IO,一个线程处理多个连接
  • AIO 异步IO,异步处理连接

Netty 对网络编程的贡献

Netty是一个Java的,基于NIO的,高性能的,异步事件驱动的通信框架。

Netty屏蔽了NIO的许多技术细节,为我们提供了一组简单易用的API,基本上我们只需要创建一个Bootstrap 或者 ServerBootstrap 然后绑定端口即可完成客户端或者服务端的配置,此外Netty预置了许多编解码方式,可以拿来即用,并且它支持大量主流的协议。

Netty支持零拷贝,为我们提供了TCP的粘包拆包问题的解决方案。

Netty的性能非常强悍,内部支持多种Reactor线程模型,能够充分利用多核CPU的优势,对基础的NIO进行了许多优化。

Netty的扩展性也极强,很多地方支持自定义实现,也支持灵活扩展。

Netty的社区活跃,经历了大规模的商业应用的挑战。

Netty 的主要用途

Netty几乎可以解决任何与网络通信相关的问题,它能够让我们简单快捷的构建起一个客户端或者服务端,完成定制化的网络开发。

应用领域: Netty被广泛的应用于互联网领域,大数据领域,游戏领域...

框架案例: 在许多框架中我们都可以看到Netty,如:Dubbo、RocketMQ、XXL-JOB、Hadoop...

Netty的主要用途:

  • HTTP、HTTPS的客户端或者服务器
  • WebSocket 长连接协议
  • 自定义RPC通信协议(各种自定义私有协议)
  • UDP广播
  • 服务间心跳检测
  • ...

Netty 的核心组件

大家想要玩转Netty必须熟悉其中的几大核心组件,

  • Bootstrap 和 ServerBootstrap

    引导类,主要作用是对应用程序进行配置,启动程序

    • Bootstrap 客户端的引导类

      调用 bind()(连接UDP)和 connect()(连接TCP)方法时,会新创建一个Channel,通过这个 Channel进行通信。

    • ServerBootstrap 服务端的引导类

      调用 bind() 方法时,会创建一个ServerChannel用于接收来自客户端的连接,并且该 ServerChannel 管理多个子 Channel 用于同客户端之间的通信。

  • Channel 和 ServerChannel

    Channel 和 ServerChannel可以看作是传入或传出数据的载体。我们可以把他理解为Socket 和 ServerSocket的NIO升级版,它要比Socket更加易用,并且屏蔽其与操作系统的交互。

  • EventLoop 和 EventLoopGroup

    EventLoop 事件循环(事件驱动的核心),监听注册到Channel上的网络事件,并调用事件处理器 ChannelHandler 进行相关 I/O 操作(读写)的处理,起承上启下的作用。

    EventLoop的管理是通过EventLoopGroup来实现的。客户端一般需要一个EventLoopGroup就可以,服务端一般需要两个EventLoopGroup,一个负责管理连接,一个负责IO事件的处理。

  • ChannelHandler

    Netty 的主要组件是ChannelHandler,我们通过ChannelHandler处理入站和出站的数据,这里也是我们自定义协议的主要扩展点,它提供大量的钩子函数,我们可以编写具体的处理读写,异常等等的逻辑,当然Netty中也为我们提供大量默认的实现。

    ChannelHandler 分为处理入站数据的 ChannelInboundHandler 和出站数据的 ChannelOutboundHandler 接口。

    ChannelHandlerContext关联一个 ChannelHandler 绑定了对应的 pipeline 和 Channel 的信息。

    ChannelInitializer是一种特殊的ChannelInboundHandler,可以通过调用initChannel方法来初始化Channel,在ChannelPipeline中初始化ChannelHandler调用序列。

  • ChannelPipeline

    当 Channel 被创建时,它会被自动地分配到一个专属的 ChannelPipeline,一个 Channel 包含一个 ChannelPipeline。 ChannelPipeline 为Channel 创建一条 ChannelHandler 的链,它负责处理和拦截inbound或者outbound的事件和操作,一个 ChannelPipeline 上可以有多个 ChannelHandler。

    我们可以自定义ChannelHandler的顺序。

  • ChannelFuture

    Netty 是异步非阻塞的,所有的 I/O 操作都为异步的。所以,我们无法立刻知晓是否执行成功,但是,我们可以通过 ChannelFuture 接口的 addListener() 方法注册一个监听器 ChannelFutureListener,当操作执行成功或者失败时,监听就会自动触发返回结果。

  • Bytebuf 字节容器

    Netty 使用自建的 Bytebuf 容器,而不是使用 NIO 的 ByteBuffer 容器。 Bytebuf 中增加读写指针,无需像ByteBuffer一样每次读写切换调用flip方法,和下一次写之前调用clear方法,减少了调用开销;并且, Bytebuf支持动态扩容,当写入的数据大于ByteBuf的容量时,会动态扩容;Bytebuf还提供了高效的零拷贝机制,内存复用机制...

总结

Netty的学习需要我们明确其各个组件的功能,以及调用关系,需要对网络,操作系统等基础有一定了解,这样我们才能更好的理解IO多路复用技术、零拷贝技术、网络协议等等。我们可以从Netty下手,去弥补自己对网络、操作系统知识的不足,Netty中Reactor的线程模型也只能我们学习。当我们了解Netty的基本概念之后,就可以通过Netty去写一些经典的案例,聊天室、自定义RPC协议等等;对于一些基本的用法熟悉之后,很多框架通信模块的代码就可以读懂了,明白其为什么这么用。

感谢大家的阅读,如果感觉有帮助,帮点个赞,万分感谢!!!