你如果,缓缓把手举起来,举到顶,再突然张开五指,那恭喜你,你刚刚给自己放了个烟花

模块介绍
  1. nettybio: 阻塞网络通信demo

  1. nettynio: 引入channel(通道)、buffer(缓冲区)、selector(选择器)的概念采用事件驱动方式使用单个线程可以监听多个客户端通道改进bio模式线程阻塞等待造成的资源浪费

  1. nettydemo: Nettydemo,认识Netty初体验

  1. nettygroupchat: 使用Netty编写一个群聊系统

  1. nettyhttp: Netty的HTTP调用demo

  1. nettybytebuf: Netty缓冲区使用demo

  1. netty-decoder: Netty编解码handler调用使用示例

  1. netty-idlestate: Netty心跳使用示例

  1. netty-sticking: 自定义协议handler解决TCP传输粘包与拆包问题

  1. netty-rpc: 使用Netty自定义实现RPC通信

netty-bio模块

模拟测试采用socketbio方式进行网络通信

blocking io同步并阻塞,服务器实现模式一个连接一个线程,即客户端连接请求服务器需要启动一个线程进行处理,如果这个连接不做任何事情就会进入阻塞等待状态,造成不必要的线程开销。

用于连接数据小且连接固定系统架构

架构示意图:

netty-nio模块

nonblocking io同步非阻塞,在bio的架构上进行改进引入channel(通道)、buffer(缓冲区)、selector(选择器)的概念,采用事件驱动方式使用单个线程就可以监听多个客户端通道改进bio模式下线程阻塞等待造成的资源浪费

架构示意图:

关键select会根据不同事件,在各个channel通道上进行切换

缓冲buffer

本质上是一个可以读写数据关键)的内存块,nio读取写入数据都必须是经过buffer的。

通道channel

把通道看做流、把通道看做流、把通道看做流,重要的事情说三遍,会很好理解 nio引入的通道类似bio中流的概念不同之处在于:

  • 通道可以同时进行读写操作,而流只能读或者

NIOFileOper01: 本地文件写数据

使用ByteBuffer与FileChannel,将“hello,李嘉图”NIOFileOper01.txt文件中。

NIOFileOper02: 本地文件读数据

使用ByteBuffer(缓冲) 和 FileChannel(通道), 将 NIOFileOper01.txt中的数据读入程序,并显示控制台屏幕

NIOFileOper03: 使用一个Buffer完成文件读取

使用 FileChannel(通道) 和 方法 read , write,完成文件的拷贝

NIOFileCopy:拷贝文件 transferFrom 方法

使用 FileChannel(通道) 和 方法 transferFrom ,完成文件的拷贝

选择器Selector

核心selector能够检测多个注册的通道上是否事件发生(多个channel事件的方式可以注册同一个selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。 这样就可以做到只使用一个单线程管理多个通道。

只有在连接/通道真正有读写事件发生时,才会进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用维护多个线程。

原理图

说明

  1. 客户端连接时,会通过ServerSocketChannel得到SocketChannel。

  1. Selector进行监听select方法,返回事件发生的通道的个数

  1. socketChannel注册到Selector上,register(),一个selector上可以注册多个SocketChannel。

  1. 注册返回一个selectionKey,会和该selector关联

  1. 一步得到各个selectionKey(有事件发生)。

  1. 通过selectionKey反向获取socketChannel,方法channel()。

  1. 可以通过得到的channel,完成业务逻辑

Netty概述

异步基于事件驱动网络应用程序框架,用以快速开发高性能、高可靠网络IO程序

有了NIO为什么需要Netty?

不需要过于关注底层逻辑,对下面的sdk等进行封装,相当于简化流程化了NIO的开发过程springspringboot关系差不多。

因为 Netty 5出现重大bug,已经被官网废弃了,目前推荐使用的是Netty 4.x稳定版本。

Netty高性能架构设计

线程模型基本介绍

传统阻塞 I/O 服务模型

模型特点:

问题分析

Reactor 模式

I/O 复用结合线程池,就是 Reactor 模式基本设计思想

Reactor在一个单独的线程中运行负责监听分发事件,分发给适当的处理程序来对IO事件作出反应。它像公司的电话接线员,接听来自客户的电话并将线路转译到适当的联系人

单 Reactor 单线程
单 Reactor 多线程

在上一代的问题上进行修改,Reactor主线程只负责响应事件,不做具体的业务处理通过read读取数据后,会分发给后面的worker线程池的某个线程处理业务

主从 Reactor 多线程

针对单 Reactor 多线程模型中,Reactor单线程运行,高并发场景下容易成为性能瓶颈,可以让 Reactor 在多线程中运行

Reactor主线程MainReactor对象通过select监听连接事件,收到事件后,通过Acceptor处理连接事件。当Acceptor处理连接事件后,MainReactor将连接分配给 SubReactor,SubReactor将连接加入到连接队列进行监听,并创建Handler进行各种事件处理

Reactor模式小结
  1. 单Reactor单线程,前台接待员和服务员是同一个人,全程为客户服务

  1. 单Reactor多线程,1个前台接待员,多个服务员,接待员只负责接待。

  1. 主从Reactor多线程,多个前台接待员,多个服务生。

Netty 模型

异步模型

基本介绍

通过future监控方法func的处理过程(即:Future-Listener机制

Future-Listener机制

当Future对象刚刚创建好时,处于非完成状态调用者可以通过返回的channelFuture来获取操作执行状态注册监听函数执行完成后的操作。

常见的操作:

– 通过 isDone 方法来判断当前操作是否完成。

– 通过 isSuccess 方法来判断已完成的当前操作是否成功

– 通过 getCause 方法来获取已完成的当前操作失败原因

– 通过 isCancelled 方法来判断已完成的当前操作是否取消

– 通过 addListener 方法来注册监听器,当操作已完成(isDone),将会通知指定的监听器。

小结:相比于传统阻塞I/O,执行I/O操作后线程会被阻塞住,直到操作完成。异步处理的好处是不会造成线程阻塞,线程在I/O操作期间可以执行别的程序,在高并发情形下会稳定和更高的吞吐量

Netty 核心模块组件

ServerBootstrap、Bootstrap

Bootstrap意思是引导,一个Netty应用通常由一个Bootstrap开始,主要作用配置整个Netty程序串联各个组件,Netty中Bootstrap类是客户端程序的启动引导类, ServerBootstrap服务器启动引导类。

常用方法:

public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup):用于服务器端用来设置两个EventLoop

public B group(EventLoopGroup group):该方法用于客户端,用来设置一个EventLoop

public B channel(Class<? extends C> channelClass):该方法用来设置一个服务器端的通道实现

public B option(ChannelOption option, T value):用来给ServerChannel添加配置

public ServerBootstrap childOption(ChannelOption childOption, T value):用来接收的通道添加配置

public ServerBootstrap childHandler(ChannelHandler childHandler):业务处理类,自定义handler

public ChannelFuture bind(int inetPort):用于服务器端用来设置占用端口号

public ChannelFuture connect(String inetHost, int inetPort):用于客户端,用来连接服务器端

Future、ChannelFuture

Netty中所有的IO操作都是异步的,不能立刻得知消息是否正确处理。但是可以过一会等它执行完成或者直接注册一个监听,具体的实现就是通过Future和ChannelFuture, 他们可以注册一个监听,当操作执行成功或失败时监听会自动触发注册的监听事件。

常用的方法:

– Channel channel():返回当前正在进行IO操作的通道

– ChannelFuture sync():等待异步操作执行完毕

Channel

Netty网络通信的组件,能够用于执行网络 I/O 操作。 通过 Channel 可获得当前网络连接的通道的状态。 通过 Channel 可获得 网络连接的配置参数例如接收缓冲大小)。 Channel 提供异步的网络 I/O 操作(如建立连接,读写,绑定端口),异步调用意味着任何 I/O 调用都将立即返回,并且不保证在调用结束时所请求的 I/O 操作已完成 调用立即返回一个 ChannelFuture实例,通过注册监听器到ChannelFuture上,可以 I/O 操作成功、失败或取消回调通知调用方。 不同协议、不同的阻塞类型的连接都有不同的 Channel 类型与之对应常用的 Channel 类型:

– NioSocketChannel,异步的客户端 TCP Socket 连接。

– NioServerSocketChannel,异步的服务器端 TCP Socket 连接。

– NioDatagramChannel,异步的 UDP 连接。

– NioSctpChannel,异步的客户端 Sctp 连接。

– NioSctpServerChannel,异步的 Sctp 服务器端连接,这些通道涵盖了 UDP 和 TCP 网络 IO 以及文件 IO。

实际开发过程中,在拿到channel之后,做一个判断,看是什么连接,如(channel instanceof SocketChannel/DatagramChannel),就可以做不同的业务处理。

Selector

Netty基于Selector对象实现I/O多路复用,通过Selector一个线程可以监听多个连接的Channel事件。当向一个Selector中注册Channel后, Selector内部机制就可以自动不断地查询(Select)这些注册的Channel是否有已就绪的I/O事件(例如可读,可写,网络连接完成等), 这样程序就可以很简单地使用一个线程高效地管理多个Channel。

ChannelHandler 及其实现类

ChannelHandler是一个接口,处理 I/O 事件或拦截 I/O 操作,并将其转发到其 ChannelPipeline(业务处理链)中的下一个处理程序

ChannelHandler及其实现类一览图:

– ChannelInboundHandler 用于处理入站 I/O 事件。

– ChannelOutboundHandler 用于处理出站 I/O 操作。

– ChannelInboundHandlerAdapter 用于处理入站 I/O 事件。

– ChannelOutboundHandlerAdapter 用于处理出站 I/O 操作。

– ChannelDuplexHandler 用于处理入站和出站事件。

Pipeline 和 ChannelPipeline

ChannelPipeline 是一个 Handler 的集合,它负责处理和拦截 inbound 或者 outbound 的事件和操作,相当于一个贯穿 Netty 的链。(也可以这样理解:ChannelPipeline 是 保存 ChannelHandler 的 List,用于处理或拦截 Channel 的入站事件和出站操作)。

ChannelPipeline 实现了一种高级形式的拦截过滤器模式,使用户可以完全控制事件的处理方式,以及 Channel 中各个的 ChannelHandler 如何相互交互

在 Netty 中每个 Channel 都有且仅有一个 ChannelPipeline 与之对应,它们的组成关系如下

一个 Channel 包含了一个 ChannelPipeline,而 ChannelPipeline 中又维护了一个由 ChannelHandlerContext 组成的双向链表,并且每个ChannelHandlerContext中又关联着一个 ChannelHandler。

入站事件和出站事件在一个双向链表中,入站事件会从链表 head 往后传递最后一个入站的 handler,出站事件会从链表 tail 往前传递到最前一个出站的 handler,两种类型handler 互不干扰。

常用方法:

– ChannelPipeline addFirst(ChannelHandler… handlers),把一个业务处理类(handler)添加到链中的第一个位置

– ChannelPipeline addLast(ChannelHandler… handlers),把一个业务处理类(handler)添加到链中的最后一个位置

ChannelHandlerContext

保存Channel相关所有上下文信息,同时关联一个ChannelHandler对象。ChannelHandlerContext包含一个具体的事件处理器ChannelHandler,同时ChannelHandlerContext 中也绑定了对应的pipeline和Channel的信息,方便对ChannelHandler进行调用。

常用方法:

– ChannelFuture close(): 关闭通道

– ChannelOutboundInvoker flush(): 刷新

– ChannelFuture writeAndFlush(Object msg): 将数据写到ChannelPipeline中当前ChannelHandler的下一个ChannelHandler开始处理。

ChannelOption

  • ChannelOption.SO_BACKLOG

  • ChannelOption.SO_KEEPALIVE

  • 一直保持连接活动状态

EventLoopGroup 和其实现类 NioEventLoopGroup

  • BoosEventLoopGroup通常是一个单线程的EventLoop,EventLoop维护着一个注册了ServerSocketChannel的Selector实例,BossEventLoop不断轮询将连接事件分离出来。

  • 通常是OP_ACCEPT事件,然后将接收到的SocketChannel交给WorkerEventLoopGroup。

  • WorkerEventLoopGroup会由next选择其中一个EventLoop来将这个SocketChannel注册到其维护的Selector并对其后续的IO事件进行处理。

常用方法:

public NioEventLoopGroup(): 构造方法

public Future<?> shutdownGracefully(): 断开连接,关闭线程

Unpooled类

Netty提供一个专门用来操作缓冲区(即Netty的数据容器)的工具类。

常用方法如下

public static ByteBuf copiedBuffer(CharSequence String, Charset charset):通过给定的数据和字符编码返回一个ByteBuf对象(类似于NIO中的ByteBuffer)

Google Protobuf

Netty本身自带的 ObjectDecoder 和ObjectEncoder可以用来实现POJO对象或各种业务对象的编码和解码,底层使用的仍然是Java序列化技术,而Java序列化技术本身效率就不高,存在如下问题

Netty编解码器handler的调用机制

代码示例netty-decoder模块

使用自定义编码器解码器说明Netty的handler调用机制

结论:

  • ReplayingDecoder使用方便,但它也有一些局限性:

TCP粘包与拆包及解决方案

TCP粘包与拆包解决方案

代码示例:

Netty 核心源码剖析

只有看过Netty源码,才能说是真的掌握了Netty框架

判断是否为 2 的 n 次方

private static boolean isPowerOfTwo(int val) {

return (val &amp; –val) == val;

}

源码解析

  • Netty核心组件EventLoop源码剖析

用Netty 自己 实现 dubbo RPC

自己实现 Dubbo RPC(基于Netty)

需求说明

设计说明

  • 创建一个提供者,该类需要监听消费者请求,并按照约定返回数据。

原文地址:https://blog.csdn.net/2301_76354366/article/details/128816560

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_49671.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注