zoukankan      html  css  js  c++  java
  • 【Netty】NIO框架Netty入门

    Netty介绍

    Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

    也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。

    官网地址:http://netty.io/

    使用场景

    Netty之所以能成为主流的NIO框架,是因为它有下面的优点:

    • NIO的类库和API使用难度较高,Netty进行了封装,容易上手
    • 高性能,功能强大,支持多种编解码功能,支持多种主流协议
    • 成熟,稳定,已经在多个大型框架中使用(dubbo,RocketMQ,Hadoop,mycat,Spring5)
    • …..

    简单入门

    我们编写一个服务端和客户端,客户端往服务端发送一条消息,消息传输先用字符串进行传递,服务端收到客户端发送的消息,然后回复一条消息。

    首先编写服务端代码:

    public class ImServer {
        public void run(int port) {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() { 
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast("decoder", new StringDecoder());
                            ch.pipeline().addLast("encoder", new StringEncoder());
                            ch.pipeline().addLast(new ServerStringHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            try {
                ChannelFuture f = bootstrap.bind(port).sync();
                 f.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                workerGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();
            }
        }
    }
    • 通过ServerBootstrap 进行服务的配置,和socket的参数可以通过ServerBootstrap进行设置。
    • 通过group方法关联了两个线程组,NioEventLoopGroup是用来处理I/O操作的线程池,第一个称为“boss”,用来accept客户端连接,第二个称为“worker”,处理客户端数据的读写操作。当然你也可以只用一个NioEventLoopGroup同时来处理连接和读写,bootstrap.group()方法支持一个参数。
    • channel指定NIO方式
    • childHandler用来配置具体的数据处理方式 ,可以指定编解码器,处理数据的Handler
    • 绑定端口启动服务

    消息处理:

    /**
     * 消息处理
     */
    public class ServerStringHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            System.err.println("server:" + msg.toString());
            ctx.writeAndFlush(msg.toString() + "你好");
        }
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }

    启动服务,指定端口为8888:

    public static void main(String[] args) {
        int port = 8888;
        new Thread(() -> {
            new ImServer().run(port);
        }).start();
    }

    编写客户端连接逻辑:

    public class ImConnection {
        private Channel channel;
        public Channel connect(String host, int port) {
            doConnect(host, port);
            return this.channel;
        }
        private void doConnect(String host, int port) {
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                Bootstrap b = new Bootstrap();
                b.group(workerGroup);
                b.channel(NioSocketChannel.class);
                b.option(ChannelOption.SO_KEEPALIVE, true);
                b.handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {    
                        ch.pipeline().addLast("decoder", new StringDecoder());
                        ch.pipeline().addLast("encoder", new StringEncoder());
                        ch.pipeline().addLast(new ClientStringHandler());
                    }
                });
                ChannelFuture f = b.connect(host, port).sync();
                channel = f.channel();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    客户端消息处理:

    /**
     * 当编解码器为字符串时用来接收数据
     */
    public class ClientStringHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            System.out.println("client:" + msg.toString());
        }
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }

    客户端启动入口,然后发送消息给服务端:

    public static void main(String[] args) {
        String host = "127.0.0.1";
        int port = 8888;
        Channel channel = new ImConnection().connect(host, port);
        channel.writeAndFlush("greenSniper");
    }

    测试步骤如下:

    1. 首先启动服务端
    2. 启动客户端,发送消息
    3. 服务端收到消息,控制台有输出server:greenSniper
    4. 客户端收到服务端回复的消息,控制台有输出client:greenSniper你好
  • 相关阅读:
    Loadrunner自带协议分析工具:Protocol Advisor
    selenium+python学习总结
    第三篇 HTML 表单及表格
    第二篇 HTML 常用元素及属性值
    第一篇 HTML 认识HTML
    int 问号的使用
    uploadify 上传文件插件
    poj3728 The merchant
    最大公约数
    Bzoj1529/POI2005 ska Piggy banks
  • 原文地址:https://www.cnblogs.com/tangzhe/p/9398473.html
Copyright © 2011-2022 走看看