欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Netty

程序员文章站 2022-01-06 07:44:55
目录一、Netty 概述二、线程模型1. 单线程模型2. 线程池模型3. Netty模型三、Netty核心组件ChannelHandler 及其实现类ChannelPipelineChannelHandlerContextChannelFutureEventLoopGroup 和其实现类 NioEventLoopGroupServerBootstrap 和 Bootstrap四、简单案例一、Netty 概述Netty 是由 JBOSS 提供一个异....

目录

一、Netty 概述

二、线程模型

1. 单线程模型

2. 线程池模型

3. Netty模型

三、Netty核心组件 

ChannelHandler 及其实现类

ChannelPipeline

ChannelHandlerContext

ChannelFuture

EventLoopGroup 和其实现类 NioEventLoopGroup

ServerBootstrap 和 Bootstrap

四、简单案例


一、Netty 概述

Netty 是由 JBOSS 提供一个异步的、 基于事件驱动的网络编程框架 , 简化和流程化了 NIO 的开发过程

Netty
NIO缺点

  • NIO 的类库和 API 繁杂,使用麻烦。你需要熟练掌握 Selector、ServerSocketChannel、SocketChannel、ByteBuffer 等.可靠性不强,开发工作量和难度都非常大
  • NIO 的 Bug。例如 Epoll Bug,它会导致 Selector 空轮询,最终导致 CPU 100%

Netty优点

  • 对各种传输协议提供统一的 API
  • 高度可定制的线程模型——单线程、一个或多个线程池
  • 更好的吞吐量,更低的等待延迟
  • 更少的资源消耗
  • 最小化不必要的内存拷贝

二、线程模型

1. 单线程模型

Netty

2. 线程池模型

    Netty

3. Netty模型

     Netty

  • Netty 抽象出两组线程池, BossGroup 专门负责接收客户端连接, WorkerGroup 专门负责网络读写操作
  • NioEventLoop 表示一个不断循环执行处理 任务的线程, 每个 NioEventLoop 都有一个 selector, 用于监听绑定在其上的 socket 网络通道。 NioEventLoop 内部采用串行化设计, 从消息的读取->解码->处理->编码->发送, 始终由 IO 线程 NioEventLoop 负责

三、Netty核心组件 

ChannelHandler 及其实现类

ChannelHandler 接口定义了许多事件处理的方法, 我们可以通过重写这些方法去实现具 体的业务逻辑
我们经常需要自定义一个 Handler 类去继承 ChannelInboundHandlerAdapter, 然后通过 重写相应方法实现业务逻辑, 我们接下来看看一般都需要重写哪些方法

  • - public void channelActive(ChannelHandlerContext ctx), 通道就绪事件
  • - public void channelRead(ChannelHandlerContext ctx, Object msg), 通道读取数据事件
  • - public void channelReadComplete(ChannelHandlerContext ctx) , 数据读取完毕事件
  • - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause), 通道发生异常事件

 

ChannelPipeline

ChannelPipeline 是一个 Handler 的集合, 它负责处理和拦截 inbound 或者 outbound 的事 件和操作, 相当于一个贯穿 Netty 的链

  • - ChannelPipeline addFirst(ChannelHandler... handlers), 把一个业务处理类(handler) 添加到链中的第一个位置
  • - ChannelPipeline addLast(ChannelHandler... handlers), 把一个业务处理类(handler) 添加到链中的最后一个位置

Netty


ChannelHandlerContext

这 是 事 件 处 理 器 上 下 文 对 象 , Pipeline 链 中 的 实 际 处 理 节 点 。 每 个 处 理 节 点ChannelHandlerContext中 包 含 一 个 具 体 的 事 件 处 理 器 ChannelHandler , 同 时 ChannelHandlerContext 中也绑定了对应的 pipeline 和 Channel 的信息,方便对 ChannelHandler 进行调用。 常用方法如下所示

  • - ChannelFuture close(), 关闭通道
  • - ChannelOutboundInvoker flush(), 刷新
  • - ChannelFuture writeAndFlush(Object msg) , 将 数 据 写 到 ChannelPipeline 中 当 前
  • - ChannelHandler 的下一个 ChannelHandler 开始处理(出站)

ChannelFuture

表示 Channel 中异步 I/O 操作的结果, 在 Netty 中所有的 I/O 操作都是异步的, I/O 的调 用会直接返回, 调用者并不能立刻获得结果, 但是可以通过 ChannelFuture 来获取 I/O 操作 的处理状态。 常用方法如下所示

  • Channel channel(), 返回当前正在进行 IO 操作的通道
  • ChannelFuture sync(), 等待异步操作执行完毕

EventLoopGroup 和其实现类 NioEventLoopGroup

EventLoopGroup 是一组 EventLoop 的抽象, Netty 为了更好的利用多核 CPU 资源, 一般 会有多个 EventLoop 同时工作, 每个 EventLoop 维护着一个 Selector 实例。 EventLoopGroup 提供 next 接口, 可以从组里面按照一定规则获取其中一个 EventLoop 来处理任务。 在 Netty 服务器端编程中, 我们一般都需要提供两个 EventLoopGroup, 例如:

BossEventLoopGroup 和 WorkerEventLoopGroup

  • - public NioEventLoopGroup(), 构造方法
  • - public Future<?> shutdownGracefully(), 断开连接, 关闭线程

ServerBootstrap 和 Bootstrap

ServerBootstrap 是 Netty 中的服务器端启动助手,通过它可以完成服务器端的各种配置; Bootstrap 是 Netty 中的客
户端启动助手, 通过它可以完成客户端的各种配置。 常用方法如下 所示
 

  • - public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup),该方法用于服务器端, 用来设置两个 EventLoop
  • - public B group(EventLoopGroup group) , 该方法用于客户端, 用来设置一个 EventLoop
  • - public B channel(Class<? extends C> channelClass), 该方法用来设置一个服务器端的通道实现
  • - public <T> B option(ChannelOption<T> option, T value), 用来给 ServerChannel 添加配置
  • - public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value), 用来给接收到的通道添加配置
  • - public ServerBootstrap childHandler(ChannelHandler childHandler), 该方法用来设置业务处理类(自定义的 handler)
  • - public ChannelFuture bind(int inetPort) , 该方法用于服务器端, 用来设置占用的端口号
  • - public ChannelFuture connect(String inetHost, int inetPort) 该方法用于客户端, 用来连接服务器端

四、简单案例

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

/**
 * @description 接收客户端请求,打印在控制台
 */
public class NettyServer {

    public static void main(String[] args) throws InterruptedException {
        // 1. 创建2个线程池对象
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(); //负责接收用户连接
        NioEventLoopGroup workGroup = new NioEventLoopGroup(); // 负责处理用户的IO读写
        // 2. 创建启动引导类
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // 3. 设置启动引导类
                            // 添加到组中,2个线程组,第一个负责用户连接,第二个负责IO读写
        serverBootstrap.group(bossGroup,workGroup)
                // 设置通道 类型
                .channel(NioServerSocketChannel.class)
                // 绑定一个监听
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    // 当通道 被创建 时,执行此方法
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                         // 一个通道 对应一个 pipeline,  pipeline 贯穿整个netty, 里面有很多个 ChannelHandler(业务处理类)去执行
                        ChannelPipeline pipeline = nioSocketChannel.pipeline();
                        // 绑定编码
                        pipeline.addLast(new StringEncoder());
                        pipeline.addLast(new StringDecoder());

                        // 绑定业务逻辑  SimpleChannelInboundHandler 是一个  ChannelHandler
                        pipeline.addLast(new SimpleChannelInboundHandler<String>() {
                            @Override
                            protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
                                // 获取入栈信息,打印客户端 传递的数据
                                System.out.println(s);
                            }
                        });
                    }
                });


        // 4. 启动引导类绑定端口
        ChannelFuture channelFuture = serverBootstrap.bind(9999).sync();
        // 5. 关闭通道
        channelFuture.channel().closeFuture();
    }
}
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;

/**
 * @description 客户端给服务端发送数据
 */
public class NettyClient {

    public static void main(String[] args) throws InterruptedException {
        // 1. 创建 连接池对象
        NioEventLoopGroup group = new NioEventLoopGroup();

        // 2. 创建客户端 的启动引导类 BootStrap
        Bootstrap bootstrap = new Bootstrap();

        // 3. 配置启动引导类
        bootstrap.group(group)
                // 设置通道为NIO
                .channel(NioSocketChannel.class)
                // 设置channel 初始化监听
                .handler(new ChannelInitializer<Channel>() {
                    // 当channel初始化时,会执行
                    @Override
                    protected void initChannel(Channel channel) throws Exception {
                        ChannelPipeline pipeline = channel.pipeline();
                        // 设置编码
                        pipeline.addLast(new StringEncoder());
                    }
                });


        // 4. 使用启动引导类连接服务器,获取一个channel
        Channel channel = bootstrap.connect("127.0.0.1", 9999).channel();
        // 5. 循环写数据给服务器
        while (true){
            // 给服务器写数据
            channel.writeAndFlush("helo server, this is client...");
            Thread.sleep(2000L);
        }
    }
}

 

 

 

 


 

本文地址:https://blog.csdn.net/NaShiYu/article/details/112211367