Netty总结
2021-04-08 08:25
标签:协议 异常 保持活动 nio 职责 弹性 情况下 监听 int ------------恢复内容开始------------ netty是JBoss提供的开源网络编程框架,提供异步的、基于事件驱动的网络应用程序框架和工具。 架构 使用了典型的三层网络架构,Reactor 通信调度层 -> 职责链 PipeLine -> 业务逻辑处理层 Reactor层主要监听网络的读写和连接操作,负责将网络层的数据 读取到内存缓冲区中,然后触发各种网络事件,例如连接创建、连接激活、读事 件、写事件等等,将这些事件触发到 PipeLine 中,由 PipeLine 充当的职责链来 进行后续的处理。涉及到的类包括:Reactor 线程 NioEventLoop 以及其父类、NioSocketChannel/NioServerSocketChannel 以及其父 类、ByteBuffer 以及由其衍生出来的各种 Buffer、Unsafe 以及其衍生出的各种内 部类等 Pipeline层负责事件在职责链中有序的传播,职责链可以选择监听和处理自己关心的事件,它可以拦截处理和向 后 / 向前传播事件,不同的应用的 Handler 节点的功能也不同,通常情况下,往往会开发编解码 Hanlder 用于消息的编解码,它可以将外部的协议消息转换成内部 的 POJO 对象,这样上层业务侧只需要关心处理业务逻辑即可,不需要感知底层 的协议差异和线程模型差异,实现了架构层面的分层隔离。 Service层有纯粹的业务逻辑 处理,例如订单处理;也有应用层协议管理,例如 HTTP 协议、FTP 协议等。 netty的io线程就是NioEventLoop,它聚合了多路复用器 Selector,可以同时并发处理成百上千个客户端连接。 当线程从某客户端 Socket 通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。由于读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于频繁 I/O 阻塞导致的线程挂起。 一个 I/O 线程可以并发处理 N 个客户端连接和读写操作,这从根本上解决了传统同步阻塞 I/O 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。 当然,实际中可以使用NioEventLoopGroup线程组,可以并发处理的客户端就非常多了。 基于主从 Reactors 多线程模型,如下图 MainReactor 负责客户端的连接请求,并将请求转交给 SubReactor。 SubReactor 负责相应通道的 IO 读写请求。 非 IO 请求(具体逻辑处理)的任务则会直接写入队列,等待 worker threads 进行处理 具体中,可以申请一个bossGroup和一个workerGroup 异步的概念:在同步中一个线程请求一种资源,如果没有请求到,就会一直等待,直到请求到为止;但异步的话,如果没有请求到,就会转手去做其他的事,直到等有了资源才会继续进行。 CallBack CallBack是异步编程常用的一种技术。 CallBack被传入某个方法中,该方法执行结束,则调用CallBack。类似的 技术,在javascript中被广泛使用 这些回调方法,可以从一个调用者线程放入到其他的不同线程中。因此,无法保证究竟在什么时候会回调用到 FetchCallback中的哪个方法。 回调方式面临一个这样的问题,即 当具有不同回调方法的异步方法,链式的放在一起时(即), 很容易导致代 码的混淆,易读性很差。 当然,代码易用性和可读性是两码事。例如,基于Javascript的Node.js,虽然大量的使用 回调方式;但是,却能很方便的使用它去写应用,代码可读性也很好。 Futures 第二中方式就是使用Futures。 Future是一种抽象,它表示在某个条件下,这个值变得有效或者可用。 Future对象 要么表示某个计算结果,要么就表示计算失败的某种异常 某些时候,使用Future会显得不太优雅,因为你不得不隔一段时间就去检查一下Future的状态以观察它是否执行完成;相比之下, callback则不会这样,它实在某种执行完成后,直接去触发某种相应的操作。 服务端 步骤1:创建ServerBootStrap 实例 步骤2:设置并绑定 Reactor 线程池:EventLoopGroup,EventLoop 就是处理所有注册到本线程的 Selector 上面的 Channel,会有主从两个EventLoopGroup。 步骤3:设置并绑定服务端的 channel 步骤4和5:创建处理网络事件的 ChannelPipeline 和 handler,网络时间以流的形式在其中流转,handler 完成多数的功能定制:比如编解码 SSl 安全认证,handle是自己写的。 步骤6:绑定并监听端口 步骤7:轮询准备就绪的channel,由 Reactor 线程:NioEventLoop 执行 pipline 中的方法,最终调度并执行 channelHandler 客户端 客户端和服务器端基本一致,但步骤6中,不会绑定端口,而是根据主机名和端口号连接。 传输服务,支持 BIO 和 NIO。 容器集成,支持 OSGI、JBossMC、Spring、Guice 容器。 协议支持,HTTP、Protobuf、二进制、文本、WebSocket 等一系列常见协议都支持。还支持通过实行编码解码逻辑来实现自定义协议。 Core 核心,可扩展事件模型、通用通信 API、支持零拷贝的 ByteBuf 缓冲对象。 服务器 客户端 Netty总结 标签:协议 异常 保持活动 nio 职责 弹性 情况下 监听 int 原文地址:https://www.cnblogs.com/lovejune/p/12430271.htmlNetty概述
Netty的IO模型
Netty的线程模型
异步设计
Netty的执行流程
Netty的功能特性
Netty入门案例
package com.liuxinghang.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyServer1 {
public static void main(String[] args) throws InterruptedException {
//创建一个线程组,接收客户端的连接
EventLoopGroup bossGroup=new NioEventLoopGroup();
//创建一个线程组,处理网络操作
EventLoopGroup workerGroup=new NioEventLoopGroup();
//创建启动对象来配置参数
ServerBootstrap b=new ServerBootstrap();
b.group(bossGroup,workerGroup) //设置两个线程组
.channel(NioServerSocketChannel.class) //使用NioServerSocketChannel作为服务器通道的实现
.option(ChannelOption.SO_BACKLOG,128) //设置线程队列中等待连接的个数
.childOption(ChannelOption.SO_KEEPALIVE,true) //保持活动连接状态
.childHandler(new ChannelInitializer
package com.liuxinghang.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
public class NettyServerHandle1 extends ChannelInboundHandlerAdapter{
//读取数据的事件
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("server:"+ctx);//输出上下文内容
ByteBuf buf= (ByteBuf) msg;
System.out.println("客户端发来的消息:"+buf.toString(CharsetUtil.UTF_8));
}
//数据读取完毕事件
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//向客户端返回数据
ctx.writeAndFlush(Unpooled.copiedBuffer("就是没钱",CharsetUtil.UTF_8));
}
//处理异常
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
package com.liuxinghang.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class NettyClient1 {
public static void main(String[] args) throws InterruptedException {
//创建一个线程组
EventLoopGroup group=new NioEventLoopGroup();
//创建客户端的启动类
Bootstrap b=new Bootstrap();
//设置线程组
b.group(group)
.channel(NioSocketChannel.class)//设置客户端通道的实现类
.handler(new ChannelInitializer
package com.liuxinghang.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
public class NettyClientHandle1 extends ChannelInboundHandlerAdapter{
//通道就绪事件,就绪就可以写出消息了
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client:"+ctx);
ctx.writeAndFlush(Unpooled.copiedBuffer("老板,还钱吧", CharsetUtil.UTF_8));
}
//读取数据的时间
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf= (ByteBuf) msg;
System.out.println("服务器发来的消息:"+buf.toString(CharsetUtil.UTF_8));
}
}