Netty

Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

使用场景:

Reactor主从多线程模型

stateDiagram    state "用户端" as Client {        [*] --> Client1 : 用户端 1        [*] --> Client2 : 用户端 2        [*] --> Client3 : 用户端 3    }        state "事件分离器" as EventDispatcher {        MainReactor : Main Reactor Acceptor Thread Pool        SubReactor : Sub Reactor IO Thread Pool        MainReactor --> SubReactor : 触发 IO 事件        MainReactor --> Auth : 认证 (Auth)        MainReactor --> SLA : 服务质量 (SLA)    }    state "Handlers" as Handlers {        [*] --> Handler1 : Handler 1        [*] --> Handler2 : Handler 2        [*] --> Handler3 : Handler 3    }    Client --> MainReactor : 发起事件    SubReactor --> Handlers : 分发到 Handler

特性

分类特性
设计统一的API,支持多种传输类型,阻塞的和非阻塞的;简单而强大的线程模型;真正的无连接数据报套接字支持;链接逻辑组件以支持复用
性能拥有比Java的核心API更高的吞吐量以及更低的延迟;得益于池化和复用,拥有更低的资源消耗;最少的内存复制
健壮性不会因为慢速、快速或者超载的连接而导致OutofMemoryError;消除在高速网络中NIO应用程序常见的不公平读/写比率

核心组件

批注 2020-07-04 092924

组件和设计

Channel

它代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件)的开放连接,如读操作和写操作

EventLoop

批注 2020-07-05 094441

一个EventLoop在它的生命周期内只和一个Thread绑定 这个Thread会处理EventLoop所有的IO事件

一个Channel对应一个EventLoop 一个EventLoop有一个或多个Channel

ChannelFuture

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

属于同一个Channel的操作都能保证按调用的顺序执行

ChannelHandler

ChannelHandler 为 Netty 中最核心的组件,它充当了所有处理入站和出站数据的应用程序逻辑的容器。ChannelHandler 主要用来处理各种事件,这里的事件很广泛,比如可以是连接、数据接收、异常、数据转换等

classDiagram  ChannelHandler <-- ChannelInboundHandler: 继承  ChannelHandler <-- ChannelHandlerAdapter: 继承  ChannelHandler <-- ChannelOutboundHandler: 继承  ChannelInboundHandler <.. ChannelInboundHandlerAdapter: 实现  ChannelHandlerAdapter <-- ChannelInboundHandlerAdapter: 继承  ChannelHandlerAdapter <-- ChannelOutboundHandlerAdapter: 继承  ChannelOutboundHandler <.. ChannelOutboundHandlerAdapter: 实现

ChannelPipeline

ChannelPipeline 为 ChannelHandler 链提供了一个容器并定义了用于沿着链传播入站和出站事件流的 API

在netty中,有两种消息发送方式

编码器解码器

ServerBootStrap

Server端需要两组EventLoop

批注 2020-07-05 100502

异常处理

线程模型

线程模型确定了代码的执行方式

线程池模型

线程池管理着一些线程,当任务被提交时,就会被分配给其中一个线程进行处理。

这种模型不能消除由上下文切换所带来的开销

EventLoop

for (;;) {    Runnable task = takeTask();    if (task != null) {        task.run();        updateLastExecutionTime();    }    if (confirmShutdown()) {        break;    }}

一个EventLoop 由 永远都不会变动的一个 Thread 驱动

任务调度

Channel ch = ...ScheduledFuture<?> future = ch.eventLoop().schedule(  ← --  创建一个Runnable以供调度稍后执行  new Runnable() {   @Override  public void run() {  ← --  要执行的代码    System.out.println("60 seconds later");   }}, 60, TimeUnit.SECONDS);  ← --  调度任务在从现在开始的60 秒之后执行

线程管理

当一个任务交由 eventloop 执行时,如果当前线程是 eventloop 所属的线程,则就直接执行了。如果当前线程不是 eventloop 所属的线程,则将任务放入到任务队列中,等待 eventloop 线程来执行

所以一定不能将一个长时间运行的任务放入到执行队列中 否则EventLoop会被阻塞

线程分配

异步传输

阻塞传输

单元测试

EmbeddedChannel

批注 2020-07-10 105859

EmbeddedChannel channel = new EmbeddedChannel(new EchoServerHandler());channel.writeInbound("hello"); // 入站数据assertTrue(channel.finish()); // 标记为完成String outData = channel.readOutbound(); // 出站数据assertEquals("hello",outData);