栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Netty编程(一)—— 初识Netty+超全注释

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Netty编程(一)—— 初识Netty+超全注释

Netty编程(一)—— 初识Netty+超全注释

文章目录
  • Netty编程(一)—— 初识Netty+超全注释
    • 什么是Netty
    • Hello World
      • 服务端
      • 客户端
      • 执行流程
      • 组件解释

之前的博客介绍了NIO网络编程的相关知识,从这篇博客开始,我将开始介绍Netty的相关知识。

什么是Netty

Netty 是一个异步的、基于事件驱动的网络应用框架,可用于快速开发可维护、高性能的网络服务器和客户端

  • 基于事件驱动意思是底层实现采用多路复用技术(selector),事件发生时才需要进行处理
  • 异步是指使用了多线程完成方法调用和处理结果相分离,并不是异步IO
Hello World

学习一个技术或者框架,可以先从hello world开始了解它,然后一步一步进行学习。下面就先通过一段最基础的Netty代码来初始Netty,这段代码可以看作Netty的Hello World,它分为服务器端和客户端两部分,首先来看服务端的代码

服务端
public class HelloServer {
    public static void main(String[] args) {
        // 1、服务器端的启动器,负责装配下方的netty组件,启动服务器
        new ServerBootstrap()
                // 2、创建 NioEventLoopGroup,可以简单理解为 线程池 + Selector
                .group(new NioEventLoopGroup())
                // 3、选择服务器的 ServerSocketChannel 实现
                .channel(NioServerSocketChannel.class)
                // 4、child(work) 负责处理读写,该方法决定了 child(work) 执行哪些操作(handler)
                // ChannelInitializer 处理器(仅执行一次)
                // 5、channel的作用是待客户端SocketChannel建立连接后与客户端进行读写的通道,执行initChannel初始化,作用是添加别的handler
                .childHandler(new ChannelInitializer() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {//添加handler
                        // 6、添加具体的handler
                        nioSocketChannel.pipeline().addLast(new StringDecoder());//使用StringDecoder解码,ByteBuf=>String

                        nioSocketChannel.pipeline().addLast(new SimpleChannelInboundHandler() {// 自定义handler,使用上一个处理器的处理结果
                            @Override
                            protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception 							{
                                System.out.println(s);//打印上一步转换好的字符串
                            }
                        });
                    }
                    // 7、ServerSocketChannel绑定8080端口
                }).bind(8080);
    }
}

下面对这段代码进行解读:

  1. 首先使用new ServerBootstrap()打开一个服务端的启动器,它负责装配下面的Nettty组件,同时会启动服务器
  2. group(new NioEventLoopGroup())用来创建一个事件循环组EventLoopGroup,可以把它理解成是Selector+线程池的组合
  3. channel(NioServerSocketChannel.class)选择服务器的ServerSocketChannel 实现
  4. childHandler(new ChannelInitializer()中的child可以理解成worker,是负责处理读写事件的,这个方法决定了child执行哪些操作(handler)
  5. channel的作用是待客户端SocketChannel建立连接后与客户端进行读写的通道,执行initChannel初始化,作用是添加别的handler
  6. initChannel(NioSocketChannel nioSocketChannel)方法是用来添加具体的handler,具体是使用nioSocketChannel.pipeline().addLast来添加,代码中添加了第一个handler是解码,将客户端发来的数据变成String,添加了第二个handler是自定义handler,并且这个handler需要使用上一个解码handler的结果。
  7. bind(8080)最后使用bind方法对端口号进行绑定
客户端
public class HelloClient {
    public static void main(String[] args) throws InterruptedException {
        //1、启动类
        new Bootstrap()
                //2、添加EventLoop
                .group(new NioEventLoopGroup())
                // 3、选择客户 Socket 实现类,NioSocketChannel 表示基于 NIO 的客户端实现
                .channel(NioSocketChannel.class)
                // 4、添加处理器   ChannelInitializer 处理器(仅执行一次)
                // 它的作用是待客户端SocketChannel建立连接后,执行initChannel以便添加更多的处理器
                .handler(new ChannelInitializer() {//初始化器会在连接建立后被调用,调用后就会执行下面的initChannel
                    @Override
                    protected void initChannel(NioSocketChannel channel) throws Exception {
                        // 消息会经过通道 handler 处理,这里是将 String => ByteBuf 编码发出
                        channel.pipeline().addLast(new StringEncoder());
                    }
                })
                // 指定要连接的服务器和端口
                .connect(new InetSocketAddress("localhost", 8080))
                // Netty 中很多方法都是异步的,如 connect
                // 这时需要使用 sync 方法等待 connect 建立连接完毕,是一个阻塞方法,知道连接建立
                .sync()
                // 获取 channel 对象,它即为通道抽象,可以进行数据读写操作
                .channel()
                // 写入消息并清空缓冲区,不管收发数据,都会走handle,调用处理器内部的方法
                .writeAndFlush("hello world");//把字符串转成了bytebuf
    }
}

可以看到其实客户端代码与服务端代码类似,下面对这段客户端的代码进行解读:

  1. new Bootstrap()启动一个客户端
  2. group(new NioEventLoopGroup())打开一个事件循环组,可以向其中添加handler
  3. channel(NioSocketChannel.class)选择客户 Socket 实现类,NioSocketChannel 表示基于 NIO 的客户端实现
  4. handler(new ChannelInitializer()添加 ChannelInitializer 处理器,它的作用是待客户端SocketChannel 建立连接 后,执行initChannel以便添加更多的处理器
  5. connect(new InetSocketAddress("localhost", 8080))指定要连接的服务器和端口
  6. sync()的作用是阻塞,他等待connect连接完毕
  7. channel()获取 channel 对象,它即为通道抽象,可以进行数据读写操作
  8. writeAndFlush("hello world")写入消息并清空缓冲区,无论收发数据,都会通过handle,调用处理器内部的方法
执行流程


有以下几点执行顺序与代码顺序不同:

  1. 服务器端初始化了ChannelInitializer 处理器后,会执行最后一行的bind方法进行绑定端口号,之后等待客户端的连接
  2. 客户端初始化ChannelInitializer后会去执行connect方法连接服务端,连接未成功之前会阻塞住,在连接成功后会立即执行上面的initChannel方法来添加handler
  3. 客户端拿到channel连接对象后发送数据"hello world",然后添加handler会把String转成ByteBuf(类似于ByteBuffer)后发送给服务端
  4. 服务端发现有读事件发生后,会启用事件循环组EventLoopGroup中的一个EventLoop去处理这个读事件,调用具体的handler进行处理
组件解释
  • eventLoop 可以理解为处理数据的工人

    • eventLoop 可以管理多个 channel 的 io 操作,并且一旦 eventLoop 负责了某个 channel,就会将其与channel进行绑定(channel使用工人1发送数据了,之后channel要接收数据,那么还是使用工人1进行处理),即以后该 channel 中的 io 操作都由该 eventLoop 负责,这是为了线程安全,防止消息覆盖了
    • eventLoop 既可以执行 io 操作,也可以进行任务处理,每个 eventLoop 有自己的任务队列,队列里可以堆放多个 channel 的待处理任务
    • eventLoop 按照 pipeline 顺序,依次按照 handler 的规划(代码)处理数据,可以为每个 handler 指定不同的 eventLoop
  • handler 可以理解为数据的处理工序

    • 工序有多道,合在一起就是 pipeline(传递途径),pipeline 负责发布事件(读、读取完成…)传播给每个 handler, handler 对自己感兴趣的事件进行处理(重写了相应事件处理方法)

    • pipeline 中有多个 handler,处理时会依次调用其中的 handler

    • handler 分 Inbound 和 Outbound 两类

      • Inbound 入站,写入
      • Outbound 出站,写出
  • channel 可以理解为数据的通道

  • msg 理解为流动的数据,最开始输入是 ByteBuf,但经过 pipeline 中的各个 handler 加工,会变成其它类型对象,最后输出又变成 ByteBuf

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/582396.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号