0
点赞
收藏
分享

微信扫一扫

Netty概念与应用

Xin_So 2022-01-24 阅读 96

Netty 是由 JBOSS 提供一个异步的、 基于事件驱动的网络编程框架。

一,Netty线程模型

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

二,核心组件

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中可以有多个handler,但是对于已经存在的ChannelPipeline只会提供addFirst,addLast前插与后插两种方式。

ChannelHandlerContext

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

ChannelFuture

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

EventLoopGroup 和其实现类 NioEventLoopGroup

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

ServerBootstrap 和 Bootstrap

ServerBootstrap 是 Netty 中的服务器端启动助手,通过它可以完成服务器端的各种配置; Bootstrap 是 Netty 中的客户端启动助手, 通过它可以完成客户端的各种配置。

三,简单实现应用

server端

  //1.创建2个线程池对象
        //bossGroup 负责接收用户连接
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        //workGroup 负责处理用户的io读写操作
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        //2.创建启动引导类
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        //3.设置启动引导类
        //添加到组中,两个线程池,第一个位置的线程池就负责接收,第二个参数就负责读写
        serverBootstrap.group(bossGroup,workGroup)
                //给我们当前设置一个通道类型
                .channel(NioServerSocketChannel.class)
                //绑定一个初始化监听
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    //事件监听Channel通道
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        //获取pipeLine
                        ChannelPipeline pipeline = nioSocketChannel.pipeline();
                        //绑定编码
                        pipeline.addFirst(new StringEncoder());
                        pipeline.addLast(new StringDecoder());
                        //绑定我们的业务逻辑
                        pipeline.addLast(new SimpleChannelInboundHandler<String>() {
                            protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
                                //获取入栈信息,打印客户端传递的数据
                                System.out.println(msg);
                            }
                        });
                    }
                });

        //4.启动引导类绑定端口
        ChannelFuture future = serverBootstrap.bind(9999).sync();

        //5.关闭通道
        future.channel().closeFuture().sync();

Client端

//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是否初始化
                    protected void initChannel(Channel channel) throws Exception {
                        //设置编码
                        channel.pipeline().addLast(new StringEncoder());
                    }
                });

        //4.使用启动引导类连接服务器 , 获取一个channel
        Channel channel = bootstrap.connect("127.0.0.1", 9999).channel();

        //5.循环写数据给服务器
        while (true) {
           //给服务器写数据
            channel.writeAndFlush("hello server .. this is client ...");
            Thread.sleep(2000);
        }
举报

相关推荐

0 条评论