Netty 快速入门

1,265 阅读3分钟

本篇文章主要介绍如何快速学习、认识Netty,你也可以把它理解为 学习介绍快速入门。强烈建议你收藏此篇文章,方便后续查阅。

Netty

netty 是一个基于 NIO 模型,实现的 高性能弹性可拓展性异步事件驱动 网络应用程序框架。你可以使用她快速 开发 稳定灵活客户端服务端 应用。官方介绍请看 here

体系结构

在入手之前,我们先来看看技术的整体架构(不喜欢此节,你可以直接跳过去 [get start])
netty 体系结构 netty 架构图,图片来源于 netty 官网

核心组件

这里会列出netty核心组件,当然由于篇幅问题不会做过多讲解

ByteBuf

io.netty.buffer.ByteBuf 是 netty 自定义的二进制数据存储组件,功能类似 java.nio.ByteBuffer,但是它更加简化用户的使用。

readerIndex & writerIndex

如图所示,ByteBuf 定义了readerIndex & writerIndex 方便我们对ByteBuf读取与写入。 image.png

CompositeByteBuf

CompositeByteBuf 是虚拟的buffer,将多个buffer展现为一个简单合并的buffer。这个在多Buffer需要合成一个Buffer情况下使用时(减少内存拷贝)非常实用。

Channel

io.netty.channel 连接到网络套接字或能够进行读、写、连接和绑定等I/O操作的组件。

常用实现类
  1. NioSocketChannel 客户端 NIO selector 实现
  2. NioServerSocketChannel 服务端 NIO selector 实现

ChannelPipeline

io.netty.channel.ChannelPipeline 责任链( ChannelHandler List)模式设计,用于处理或拦截Channel的入站事件和出站操作。处理顺序如下:

ChannelOutboundHandler & ChannelInboundHandler

ChannelHandler

io.netty.channel.ChannelHandler IO事件处理器,这是我们使用最频繁的接口,为了实现我们自己的业务逻辑我们必须向pipeline中添加自己的处理器。

ChannelHandler 入站 & 出站处理
  1. ChannelInboundHandler 入站处理,在使用过程中一般使用 ChannelInboundHandlerAdapter 适配类
  2. ChannelOutboundHandler 出站处理,在使用过程中一般使用 ChannelOutboundHandlerAdapter 适配类

EventLoop

io.netty.channel.EventLoop 负责处理一个或者多个 Channel,每一个EventLoop都会绑定一个 Thread
我们常用的是 NioEventLoopGroup,其是 EventLoopGroup 实现类,NIO 模型中的 EventLoop集合。

Getting Started

终于到这一节了,这一小节会写一个简单的DEMO。相关说明也在代码里加了注释。更加详细说明可以参考 here

Echo Server

public class NettyEchoServerDemo {
    public static void main(String[] args) throws Exception {
        //多线程事件处理器,默认当前核心数 * 2
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //启动类
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)// nio socketchannel
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            //添加应用,数据处理程序 ChannelHandler
                            ch.pipeline().addLast(new EchoChannelHandler());
                        }
                    })
                    //option 用于设置NioServerSocketChannel
                    .option(ChannelOption.SO_BACKLOG, 128)
                    //childOption 用于设置获取到的Channel 也就是 NioSocketChannel
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(7).sync();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    //自定义一个 ChannelInboundHandler 
    public static class EchoChannelHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ctx.write(msg);
            ctx.flush();
        }
    }
}

Echo Client

public class NettyEchoClientDemo {
    public static void main(String[] args) throws Exception {
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //client 启动类
            Bootstrap b = new Bootstrap();
            b.group(workerGroup)
                    //SocketChannel
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() { // (4)
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            //自定义数据处理程序 ChannelHandler
                            ch.pipeline().addLast(new EchoChannelHandler());
                        }
                    })
                    .option(ChannelOption.SO_KEEPALIVE, true);
            //建立连接
            ChannelFuture f = b.connect("127.0.0.1",7).syncUninterruptibly(); // (7)
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }
    //自定义 ChannelInboundHandler
    public static class EchoChannelHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println(((ByteBuf)msg).toString(CharsetUtil.UTF_8));
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            //与服务端交互
            String name = bufferedReader.readLine();
            System.out.println(name);
            ctx.writeAndFlush(Unpooled.copiedBuffer(name.getBytes()));
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            super.channelActive(ctx);
            //首次出发,发送消息给服务端 这里需要传 ByteBuf
            ChannelFuture c = ctx.writeAndFlush(Unpooled.copiedBuffer("message".getBytes()));
            if(!c.isSuccess()){
                System.out.println(c.cause());
            }
        }
    }
}

感谢

欢迎留言指正! 内容持续更新!