Netty深入学习总览

本文是对学到的netty知识的简单总结,在之后的文章中会逐步分析netty源码,如果文中存在错误希望能够指出,谢谢。

Netty是什么

学习netty之前,首先我们来了解下什么是netty。这里简单的来说就是基于NIO实现的高性能异步的通信框架。
因为Netty是基于NIO的,所以为了更加清楚Netty里面的结构,我们回顾下NIO的线程模型,如下图:
在这里插入图片描述

了解了NIO模型和什么是netty之后,我们来了解下Netty中常用的模块:

  • 【NioEventLoopGroup】:管理 eventLoop 的生命周期,可以理解为一个线程池,内部维护了一组线程,每个线程(NioEventLoop)负责处理多个Channel 上的事件,而一个 Channel 只对应于一个线程。

  • 【NioEventLoop】:一个线程,里面维护了一个任务队列,用来处理连接和读写事件,异步支持。

  • 【Bootstrap、ServerBootstrap】:可以认为是一个Netty应用的启动类,通过它可以将Netty中的各个组件和配置连接起来,Bootstrap是客户端的启动类,ServerBootstrap是服务端的启动类。

  • 【Selector】:Netty 基于 NIO中的Selector 对象实现 I/O 多路复用,用来监听连接请求事件。

  • 【Channel】:由NIO模型可知,一个Channel对应一个客户端连接,它是客户端与服务端数据交互的通道,在Channel中,我们可以配置不同的服务端来处理不同的服务,比如:
    NioSocketChannel,异步的客户端 TCP Socket 连接。
    NioServerSocketChannel,异步的服务器端 TCP Socket 连接。
    NioDatagramChannel,异步的 UDP 连接。

  • 【ChannelPipline】:一个Channel存在一个ChannelPipline,它里面保存 ChannelHandler 的 List,用于处理或拦截 Channel 的入站事件和出站操作。

  • 【ChannelHandler】:是业务处理逻辑的实现,里面可以实现指定的接口,然后通过类似于链条的形式依次执行每个ChannelHandler的某个方法。

  • 【ChannelHandlerContext】:保存 Channel 相关的所有上下文信息,同时关联一个 ChannelHandler 对象。

  • 为了理清上面一些组件的关系,这里简单作了图【首先通过BossGroup线程组接收来自客户端的连接请求,接下来将这些请求中的事件注册到WorkerGroup中的线程根据管道pipeline中的handler去处理具体连接请求的事件,读、写、等操作】,如下图:
    在这里插入图片描述

  • 了解了上面的组件后,我们来看一下netty实现的服务端代码,如下:

public class NettyServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 创建一个线程用来接收连接
        EventLoopGroup workerGroup = new NioEventLoopGroup(); //默认创建线程数为cpu核数的两倍
        try {
            //创建服务器端的启动对象
            ServerBootstrap bootstrap = new ServerBootstrap();
            //使用链式编程来配置参数
            bootstrap.group(bossGroup, workerGroup) //设置两个线程组
                    .channel(NioServerSocketChannel.class) //使用NioServerSocketChannel作为服务器的通道实现
                    //.option(ChannelOption.SO_BACKLOG, 1024) //这里是添加一些额外的参数,比如数据缓存大小,连接数的处理
                    //.handler(new NettyServerHandler()) //这里可以添加handler
                    .childHandler(new ChannelInitializer<SocketChannel>() {//创建通道初始化对象,设置初始化参数

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //向管道中添加处理器handler
                            ch.pipeline().addLast(new NettyServerHandler());
                        }
                    });
            System.out.println("netty server start。。");
            //启动服务器(并绑定端口),bind是异步操作,sync方法是等待异步操作执行完毕
            ChannelFuture cf = bootstrap.bind(9000).sync();
            //对通道关闭进行监听,closeFuture是异步操作,通过sync方法同步等待通道关闭处理完毕,这里会阻塞等待通道关闭完成
            cf.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

  • 自定义的处理器handler,这里需要根据你自己的需要重写不同的方法,将常用的方法以给出,如下:
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("这里是客户端连接进来激活的方法");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("这里是客户端关闭激活的方法");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("这里是服务端读取客户端发送的消息,服务端触发的方法");
        //将 msg 转成一个 ByteBuf,类似NIO 的 ByteBuffer
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("客户端发送消息是:" + buf.toString(CharsetUtil.UTF_8));
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("这里是服务端读取完客户端发送的消息后,服务端触发的方法");
        ByteBuf buf = Unpooled.copiedBuffer("Hello Client".getBytes(CharsetUtil.UTF_8));
        ctx.writeAndFlush(buf);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("这里是有异常时候触发的方法");
        ctx.close();
    }
}

  • 接下来我们来看一下客户端代码的实现:
public class NettyClient {
    public static void main(String[] args) throws Exception {
        //客户端需要一个事件循环组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //创建启动类对象Bootstrap
            Bootstrap bootstrap = new Bootstrap();
            //设置相关参数
            bootstrap.group(group) //设置线程组
                    .channel(NioSocketChannel.class) // 使用NioSocketChannel作为客户端的通道实现
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //加入处理器
                            ch.pipeline().addLast(new NettyClientHandler());
                        }
                    });

            System.out.println("netty client start");
            //启动客户端去连接服务器端
            ChannelFuture cf = bootstrap.connect("127.0.0.1", 9000).sync();
            //对通道关闭进行监听
            cf.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
}

  • 客户端的NettyClinetHandler实现思路与服务端类似,这里不作说明了。

总结:Netty将NIO进行了二次封装,将NIO实现客户端与服务端通讯的代码简单化,用户只需要按照Netty给定的代码模板,只需要根据不同的需求,实现自己的handler处理器即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值