zoukankan      html  css  js  c++  java
  • 高性能NIO通信框架之Netty入门(一)


    一、不选择Java原生NIO编程的原因
    (1)NIO的类库和API复杂,使用麻烦,你需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等
    (2)需要具备其他的额外技能做铺垫,例如熟悉Java多线程编程。这是因为NIO编程涉及到Reactor模式,你必须对多线程和网络编程非常熟悉,才能编写出高质量NIO程序。
    (3)可靠性能力补齐,工作量和难度都非常大。例如客户端面临断链重连、网络闪断、半包读写、失败缓存、网络拥塞和异常码流的处理等问题,NIO编程的特点是功能开发相对容易,但是可靠性能力补齐的工作量和难度非常大。
    (4)JDK NIO的BUG,例如臭名昭著的epoll bug,它会导致Selector空轮询,最终导致CPU 100%。官方声称在JDK 1.6 版本的update 18修复了该问题,但是直到JDK 1.7版本该问题仍旧存在,只不过该BUG发生概率降低了一些而已,它并没有得到根本性解决。

    二、Netty 优点
    (1)API使用简单,开发门槛低
    (2)功能强大,预置了多种编解码功能,支持多种主流协议
    (3)定制能力强,可以通过ChannelHandler 对通信框架进行灵活地扩展
    (4)性能高,通过与其他业界主流的NIO框架对比,Netty的综合性能最优
    (5)成熟、稳定,Netty修复了已经发现的所有JDK NIO BUG,业务开发人员不需要再为NIO的BUG而烦恼
    (6)社区活跃,版本迭代周期短,发现的BUG可以被及时修复,同时,更多的新功能会加入
    (7)经历了大规模的商业应用考验,质量得到验证。Netty 在互联网、大数据、网络游戏、企业应用、电信软件的 众多行业已经得到了成功商业,证明它已经完全能够满足不同行业的商业应用了

    三、Netty服务端Demo

    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    /**
     * Netty 时间服务器服务端TimeServer
     */
    public class TimeServer {
        public void bind(int port) {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                ServerBootstrap b = new ServerBootstrap();
                b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                        .option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChildChannelHandler());
                //绑定端口,同步等待成功
                ChannelFuture f = b.bind(port).sync();
                //等待服务端监听端口关闭
                f.channel().closeFuture().sync();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //优雅退出,释放线程池资源
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    
        private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
    
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                socketChannel.pipeline().addLast(new TimeServerHandler());
            }
        }
    
        public static void main(String[] args) {
            int port = 8080;
            new TimeServer().bind(port);
        }
    
    }
    
    
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandlerAdapter;
    import io.netty.channel.ChannelHandlerContext;
    
    import java.util.Date;
    
    
    public class TimeServerHandler extends ChannelHandlerAdapter{
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf buf = (ByteBuf) msg;
            byte[] req = new byte[buf.readableBytes()];
            buf.readBytes(req);
            String body = new String(req,"UTF-8");
            System.out.println("The time server receive order : "+body);
            String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body)?new Date(System.currentTimeMillis()).toString():"BAD ORDER";
            ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
            ctx.write(resp);
        }
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.flush();
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }

    四、Netty的客户端Demo

    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    
    /**
     * Created by ThinkPad on 2019/6/17.
     */
    public class TimeClient {
        public void connect(int port,String host) {
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                Bootstrap b = new Bootstrap();
                b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true).handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new TimeClientHandler());
                    }
                });
                //发起异步连接操作
                ChannelFuture f = b.connect(host,port).sync();
                //等待客户端连接操作
                f.channel().closeFuture().sync();
            }catch (Exception e) {
                e.printStackTrace();
            }finally {
                //优雅退出,释放NIO线程组
                group.shutdownGracefully();
            }
        }
    
        public static void main(String[] args) {
            int port = 8080;
            new TimeClient().connect(port,"127.0.0.1");
        }
    }
    
    
    
    
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandlerAdapter;
    import io.netty.channel.ChannelHandlerContext;
    
    /**
     * Created by ThinkPad on 2019/6/17.
     */
    public class TimeClientHandler extends ChannelHandlerAdapter{
        private final ByteBuf firstMessage;
    
        public TimeClientHandler() {
            byte[] req = "QUERY TIME ORDER".getBytes();
            firstMessage = Unpooled.buffer(req.length);
            firstMessage.writeBytes(req);
        }
    
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.writeAndFlush(firstMessage);
        }
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf buf = (ByteBuf)msg;
            byte[] req = new byte[buf.readableBytes()];
            buf.readBytes(req);
            String body = new String(req,"UTF-8");
            System.out.println("Now is : "+body);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }

    五、测试运行结果

    先运行Netty 服务端,然后在运行Netty 客户端

    运行结果如下:

  • 相关阅读:
    操作数据库系统(OLTP)和联机分析处理系统(OLAP)的区别
    BI笔记-SSAS部署的几种方式及部署后的SSAS刷新
    概念-数据仓库与元数据
    零基础学Python 3之环境准备
    OFBiz进阶之HelloWorld(五)创建新实体
    OFBIZ bug_create-component ERROR
    OFBIZ bug_ControlServlet.java:233:ERROR
    OFBiz进阶之HelloWorld(三)CRUD操作
    OFBiz进阶之HelloWorld(二)创建热部署模块
    OFBIZ bug_ControlServlet.java:239:ERROR
  • 原文地址:https://www.cnblogs.com/lovegrace/p/11047777.html
Copyright © 2011-2022 走看看