Netty学习—概述和核心组件

一 netty概述

1.1 为什么有了NIO还有Netty
  1. NIO的缺点
  • JDK 的 NIO 底层由 epoll 实现,该实现饱受诟病的Selector 空轮询 bug 会导致 cpu 飙升 100%
  • NIO的API繁杂,使用麻烦,必须熟练掌握Selector、Channel、Buffer等相关API。并且需要熟练Java多线程编程和网络编程,才能写出高质量的NIO代码。
  • 开发工作量和难度都非常大。例如客户端的断连重连,网络闪退,半包读取,失败缓存等问题。
1.2 什么是netty

Netty is an asynchronous event-driven network application framework
for rapid development of maintainable high performance protocol servers & clients. (来自官网 https://netty.io/)
Netty 是一个异步的基于事件驱动的网络应用框架。为了快速开发高性能的服务端和客户端

  • Netty是JBoss提供的一个Java开源框架。提供了异步、基于事件驱动的网络应用框架。用于快速开发高性能、高可靠性的网络IO程序
  • Netty可以帮助你快速、简单的开发一个网络应用,相当于简化和流程化一个NIO的开发过程
  • Netty是目前最流程的NIO框架。在互联网领域、大数据分布式计算领域、游戏行业 等都有广泛的应用。比如ES、Dobbo等框架内部都是采用了Netty
    在这里插入图片描述
    从下到上解释为:
  1. 绿色部分:是netty的核心包
    • netty的零啊拷贝
    • 交互的API库
    • 可扩展的事件模型
  2. 黄色的部分 支持的相关协议
    • webSock谢谢
    • zlib / gzip 压缩
    • protobuf 。谷歌的解码编码器
    • 大文件的传输等
  3. 红色的 是支持的传输服务
1.4 Netty的优点
  • 优雅的设计、适用于各种传输类型的统一API阻塞和非阻塞Socket。基于灵活可扩展的事件模型。
  • 使用方便,有详细的JavaApi
  • 高性能、高吞吐量,延迟低,减少资源的消耗。还有零拷贝
  • 安全。完整的SSL(Secure Socket Layer,安全套接字层) /TSL (Transport LayerSecurity,传输层安全协议)和StartTLS支持的各种传输协议
  • 社区比较活跃,不断更新。
  • Netty5 已经废弃了,一般都是用netty4

二、Netty的核心组件

  • Channel
  • callback
  • Future
  • event 和ChannelHandler
2.1 Channel

channel 是Java NIO的一个基本架构。其基本的构造是 Socket,在jdk中channel是通讯载体,在netty中channel被赋予了更多的功能。

首先强调一点:NIO的Channel与Netty的Channel不是一个东西!
Netty重新设计了Channel接口,并且给予了很多不同的实现。Channel时Netty的网络抽象类,除了NIO中Channel所包含的网络I/O操作,主动建立/关闭连接,获取双方网络地址的功能外,还包含了Netty框架的功能,例如:获取Channel的EventLoop\Pipeline等。

  • Channel接口是能与一个网络套接字(或组件)进行I/0操作(读取\写入\连接\绑定)的纽带.
  • 通过Channel可以获取连接的状态(是否连接/是否打开),配置通道的参数(设置缓冲区大小等),进行I/O操作

简单的理解就是拿到了channel,就可以和客户端进行通信,具体参考了Netty Channel源码分析 和 《Netty实战》
常见的Channel类型有:

  • NioSocketChannel:代表异步的客户端TCP scoket连接 (用的最多)
  • NioServerSocketChannel:异步的服务器端 TCP Socket 连接 (用的最多)
  • NioDatagramChannel:异步的 UDP 连接
  • NioSctpChannel:异步的客户端 Sctp 连接
  • NioSctpServerChannel:异步的 Sctp 服务器端连接
  • OioSocketChannel:同步的客户端 TCP Socket 连接
  • OioServerSocketChannel:同步的服务器端 TCP Socket 连接
  • OioDatagramChannel:同步的 UDP 连接
  • OioSctpChannel:同步的 Sctp 服务器端连接
  • OioSctpServerChannel:同步的客户端 TCP Socket 连接

常见的API有:

接口名称说明
eventLoop()Channel需要注册到EventLoop的多路复用器上,用于处理I/O事件,通过eventLoop()方法可以获取到Channel注册的EventLoop。EventLoop本质上就是处理网络读写事件的Reactor线程。在Netty中,它不仅仅用来处理网络事件,也可以用来执行定时任务和用户自定义NioTask等任务。
pipeline()返回channel分配的ChannelPipeline
isActive()判断channel是否激活。
localAddress()返回本地的socket地址
remoteAddress()返回远程客户端的socket地址。
flush()将之前已写的数据冲刷到底层Channel上去。可以理解为发送数据
write(Object msg)请求将当前的msg通过ChannelPipeline写入到目标Channel中。需要注意write操作只是将消息存入到消息发送环形数组中,消息并没有发送,需要调用flush()方法才会发送
writeAndFlush(Object msg)等同于调用write()并接着调用flush()
read()从当前的Channel中读取数据到第一个inbound缓冲区中,如果数据被成功读取,触发ChannelHandler.channelRead(ChannelHandlerContext,Object)事件
writeAndFlush(Object msg)等同于调用write()并接着调用flush()
metadate()熟悉TCP协议的读者可能知道,当创建Socket的时候需要指定TCP参数,例如接收和发送的TCP缓冲区大小,TCP的超时时间。是否重用地址等。在Netty中,每个Channel对应一个物理链接,每个连接都有自己的TCP参数配置。所以,Channel会聚合一个ChannelMetadata用来对TCP参数提供元数据描述信息,通过metadata()方法就可以获取当前Channel的TCP参数配置。
writeAndFlush(Object msg)等同于调用write()并接着调用flush()
close(ChannelPromise promise)主动关闭当前连接,通过ChannelPromise设置操作结果并进行结果通知,无论操作是否成功,都可以通过ChannelPromise获取操作结果,会触发ChannelPipeline中所有ChannelHandler的ChannelHandler.close事件
parent()对于服务端Channel而言,它的父Channel为空;对于客户端Channel,它的父Channel就是创建它的ServerSocketChannel。
id()返回ChannelId对象,ChannelId是Channel的唯一标识。
2.2 回调

一个回调其实就是一个方法,一个指向已经被提供给另外一个方法的方法的引用。这使得后者可以在适当的时候调用前者。回调在广泛的编程场景中都有应用,而且也是在操作完成后通知相关方最常见的方式之一

Netty 在内部使用了回调来处理事件;当一个回调被触发时,相关的事件可以被一个 interfaceChannelHandler 的实现处理。
ChannelHandler的主要API如下:

接口名称说明
handlerAdded当把 ChannelHandler 添加到 ChannelPipeline 中时被调用
handlerRemoved当从 ChannelPipeline 中移除 ChannelHandler 时被调用
exceptionCaught当处理过程中在 ChannelPipeline 中有错误产生时被调用
channelRegistered当 Channel 已经注册到它的 EventLoop 并且能够处理 I/O 时被调用
channelUnregistered当 Channel 从它的 EventLoop 注销并且无法处理任何 I/O 时被调用
channelActive当 Channel 处于活动状态时被调用;Channel 已经连接/绑定并且已经就绪
channelInactive当 Channel 离开活动状态并且不再连接它的远程节点时被调用
channelReadComplete当Channel上的一个读操作完成时被调用
channelRead当从 Channel 读取数据时被调用
ChannelWritabilityChanged当 Channel 的可写状态发生改变时被调用
bind当请求将 Channel 绑定到本地地址时被调用
connect当请求将 Channel 连接到远程节点时被调用
disconnect当请求将 Channel 从远程节点断开时被调用
close当请求关闭 Channel 时被调用
read当请求从 Channel 读取更多的数据时被调用
flush当请求通过 Channel 将入队数据冲刷到远程节点时被调用
write当请求通过 Channel 将数据写到远程节点时被调用
2.1 Future

Future 提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问

Future最早出现于JDK的java.util.concurrent.Future,它用于表示异步操作的结果.由于Netty的Future都是与异步I/O操作相关的,因此命名为ChannelFuture,代表它与Channel操作相关.

ChannelFuture channelFuture = serverBootstrap.bind(6668).sync();
channelFuture.addListener(new ChannelFutureListener() {
     @Override
     public void operationComplete(ChannelFuture future) throws Exception {
         if (future.isSuccess()) {
             System.out.println("链接成功");
         } else {
             Throwable cause = future.cause();
             System.out.println("链接失败"+cause.getMessage());
         }
     }
});
  • 异步连接到一个远程节点
  • 注册ChannelFutureListener 到channelFuture ,以便之后到操作能够获取到通知
  • 当bind 等操作执行完,会调用ChannelFutureListener的operationComplete方法,并执行向对应的逻辑
  • 如果发生了错误,可以对错误进行处理。
2.1 Event和ChannelHandler

Netty是 一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。

对于服务器事件处理模型,通常有下面几种方式

  1. 每收到一个请求,就创建一个线程。来处理该请求
  2. 每收到一个请求,就放入到一个事件列表,让主线程通过非阻塞到方式来处理请求。

以上各种方式各有各的好处:
第一种方式,由于设计到多线程到问题,可能会遇到线程见到通信和共享资源锁到问题。而且线程本身就是稀有资源,所以性能也有一定到限制
第二种方式呢。在写程序到时候来逻辑可能比较复杂等。

事件驱动模型
事件驱驱动架构由三个基本组件构成,事件(event)、事件循环(eventLoop)、事件处理器(ChannelHandler)。事件产生后发送给事件循环,事件循环将每个事件分派给个各个事件处理器。素有事件,是按照它们们与入站或出站数据流的相关性进行分类的。所以事件A由处理器A处理,事件B将被处理器B处理。
在这里插入图片描述
  事件驱动编程是一种编程范式,这里程序的执行流由外部事件来决定。它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。另外两种常见的编程范式是(单线程)同步以及多线程编程。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值