netty 简单入门

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kang389110772/article/details/78920679

netty 简单入门

引文

因为不了解netty是什么,曾经闹过两次笑话。一次有一个兄弟说工程里没用tomcat等容器,是使用netty实现的.我当时还错判了,还有一次在rpc工程里别人问netty的版本,我又以为是一种servlet服务器,-_-||

写这个文章,是为了有初步的认识和大概的了解netty。

netty是什么

简单来说,netty是客户端和服务单交互的NIO框架。具体来说,使用netty可以快速开发出一个便捷和高效的网络交互应用,可以极大简化网络编程。netty使得网络编程和NIO变得简单易用和维护。

为什么要用及场景

今天,我们使用通用的应用程序或者类库来实现互相通讯,比如,我们经常使用一个 HTTP 客户端库来从 web 服务器上获取信息,或者通过 web 服务来执行一个远程的调用。
但是这个标准的实现没有办法很好满足的需求。我们需要实现一个异步的高效的框架,所以netty就出现了。
主要应用在互联网行业、游戏行业、大数据领域

架构简单介绍

Netty架构

  • 丰富的缓冲实现
    1. 可扩展性。 可以继承ByteBuf接口,自定义实现
    2. 透明的零拷贝。这里说的是提供了buffer组合的功能,不必像远程的NIO一样,把多个缓冲真的copy到一个缓冲里进行处理
    3. 容量扩展。 这里说的是如果消息可变,实现了一个类似StringBuffer的缓冲,可以自动增长
  • 统一的异步 I/O API 基于channel的接口进行多种实现,默认提供了NIO/OIO的TCP/UDP实现
  • 基于拦截链模式的事件模型 在实现自己的handler时候,通过覆盖handler多个方法来实现多个事件的自定义功能
  • 支持多种协议
  • 支持多种transport

简单的demo和说明

这里我们使用简单事件服务器来进行说明

  1. server handler

    public class TimeServerHandler extends ChannelInboundHandlerAdapter {
    
        /**
         * channelActivity() 方法将会在连接建立并且准备通信时调用
         * @param ctx ctx
         * @throws Exception 异常
         */
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            // 缓冲
            ByteBuf time = ctx.alloc().buffer(4);
            time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));
    
            final ChannelFuture f = ctx.writeAndFlush(time);
            // write和writeAndFlush都会返回一个ChannelFuture对象,并不会立即执行。为了保证
            // 先写再关闭,使用listener进行关闭
            f.addListener(future -> {
               assert f == future;
               ctx.close();
            });
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
    }
  2. client handler

    public class TimeClientHandler extends ChannelInboundHandlerAdapter {
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf m = (ByteBuf) msg;
            try {
                // 解析消息
                long currentTimeMillis = (m.readUnsignedInt() - 2208988800L) * 1000L;
                System.out.println(new Date(currentTimeMillis));
                ctx.close();
            } finally {
                m.release();
            }
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
    }
  3. TimeServer

    public class TimeServer {
    
        private int port;
    
        public TimeServer(int port) {
            this.port = port;
        }
    
        public void run() throws Exception {
            // NioEventLoopGroup 是用来处理I/O操作的多线程循环器
            // boss 用来处理接受进来的连接
            // worker 用来处理已经被接受的连接
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                // ServerBootstrap 是一个启动NIO的辅助启动类。
                ServerBootstrap bootstrap = new ServerBootstrap();
                bootstrap.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new ChannelInitializer<SocketChannel>() { // 用来处理已经被接受的连接
                            @Override
                            protected void initChannel(SocketChannel channel) throws Exception {
                                channel.pipeline().addLast(new TimeServerHandler());
                            }
                        })
                        .option(ChannelOption.SO_BACKLOG, 128)
                        .childOption(ChannelOption.SO_KEEPALIVE, true);
    
                // 绑定端口,开始接受进来的连接
                ChannelFuture f = bootstrap.bind(port).sync();
    
                // 等待服务器, socket关闭
                // 在这个例子中,这不会发生,但你可以优雅的关闭你的服务器
                f.channel().closeFuture().sync();
            } finally {
                workerGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();
            }
        }
    
    
        public static void main(String[] args) throws Exception {
            int port;
            if (args.length > 0) {
                port = Integer.parseInt(args[0]);
            } else {
                port = 8080;
            }
            new TimeServer(port).run();
        }
    }
  4. TimeClient

    public class TimeClient {
    
        public static void main(String[] args) throws Exception {
            String host = "127.0.0.1";
            int port = 8080;
            EventLoopGroup workerGroup = new NioEventLoopGroup();
    
            try {
                // Bootstrap和Server类似,不过不是服务单的channel, 比如客户端和无连接传输模式的channel
                Bootstrap b = new Bootstrap();
                // 如果只指定了一个group,那么这个group既是boss也是worker
                b.group(workerGroup);
                // 客户端使用的是NioSocketChannel
                b.channel(NioSocketChannel.class);
                b.option(ChannelOption.SO_KEEPALIVE, true);
                b.handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new TimeClientHandler());
                    }
                });
    
                // 启动客户端(connect替代了bind方法)
                ChannelFuture f = b.connect(host, port).sync();
    
                // 等待连接关闭
                f.channel().closeFuture().sync();
            } finally {
                workerGroup.shutdownGracefully();
            }
        }
    }

    从demo上来看,我们主要在handler中实现基于事件的各种handler, 使用ServerBootstrap和Bootstrap进行启动服务端和客户端,很像其他的B/S结构。到这里我们基本了解netty是什么,简单的应用方法,到此结束。

猜你喜欢

转载自blog.csdn.net/kang389110772/article/details/78920679