高性能IO框架Netty一-第一个Netty程序

目录

一、Netty 简介

1、Netty是什么?

2、为什么要用Netty?

3、为什么Netty使用NIO而不是AIO?

4、为什么不用Netty5

二、Hello Netty!

1、NettyServer

2、NettyServerHandler

3、NettyClient

4、NettyClientHandler

5、程序演示

6、总结


Netty作为一个高性能IO框架,基本上所有使用JAVA技术栈的大厂,底层的IO通信框架都是通过Netty实现的。例如 dubbo,Spring gateway等等。所以不管是已经工作的还是在校学生。学会Netty,在你面试大厂的时候,无疑都是加分项。是所有从事JAVA工作的必备技能。完整介绍Netty的书籍不是很多,主要有华为大牛李林峰的《Netty权威指南》,和上年刚出的《Netty进阶:跟着案例学Netty》,以及国外的译本《Netty实战》。初学者建议选择《Netty权威指南》或者《Netty实战》。等学会之后在看《Netty进阶》。

中间一个月比较忙,鸽了三天,今天开始更新Netty相关文章.

一、Netty 简介

1、Netty是什么?

以下资料摘自百度百科,总结的已经比较好了。

Netty是由Jboss提供的一个Java开源框架,现为 Github上的独立项目。Netty提供异步的、时间驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

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

2、为什么要用Netty?

1、虽然JAVA NIO框架提供了 多路复用IO的支持,但是并没有提供上层“信息格式”的良好封装。例如前两者并没有提供针对 Protocol Buffer、JSON这些信息格式的封装,但是Netty框架提供了这些数据格式封装(基于责任链模式的编码和解码功能);

2、NIO的类库和API相当复杂,使用它来开发,需要非常熟练地掌握Selector、ByteBuffer、ServerSocketChannel、SocketChannel等,需要很多额外的编程技能来辅助使用NIO,例如,因为NIO涉及了Reactor线程模型,所以必须必须对多线程和网络编程非常熟悉才能写出高质量的NIO程序

3、要编写一个可靠的、易维护的、高性能的NIO服务器应用。除了框架本身要兼容实现各类操作系统的实现外。更重要的是它应该还要处理很多上层特有服务,例如:客户端的权限、还有上面提到的信息格式封装、简单的数据读取,断连重连,半包读写,心跳等等,这些Netty框架都提供了响应的支持。

4、高性能,拥有比核心 Java API 更好的吞吐量,较低的延时,并且资源消耗更少,这个得益于共享池和重用,减少内存拷贝,实现0拷贝。

4、JAVA NIO框架存在一个poll/epoll bug:Selector doesn’t block on Selector.select(timeout),不能block意味着CPU的使用率会变成100%(这是底层JNI的问题,上层要处理这个异常实际上也好办)。当然这个bug只有在Linux内核上才能重现。

这个问题在JDK 1.7版本中还没有被完全解决,但是Netty已经将这个bug进行了处理。

这个Bug与操作系统机制有关系的,JDK虽然仅仅是一个兼容各个操作系统平台的软件,但在JDK5和JDK6最初的版本中(严格意义上来将,JDK部分版本都是),这个问题并没有解决,而将这个帽子抛给了操作系统方,这也就是这个bug最终一直到2013年才最终修复的原因(JDK7和JDK8之间)。

3、为什么Netty使用NIO而不是AIO?

Netty不看重Windows上的使用,在Linux系统上,AIO的底层实现仍使用EPOLL,没有很好实现AIO,因此在性能上没有明显的优势,而且被JDK封装了一层不容易深度优化。

AIO还有个缺点是接收数据需要预先分配缓存, 而不是NIO那种需要接收时才需要分配缓存, 所以对连接数量非常大但流量小的情况, 内存浪费很多。

据说Linux上AIO不够成熟,处理回调结果速度跟不上处理需求,有点像外卖员太少,顾客太多,供不应求,造成处理速度有瓶颈。

作者原话:

Not faster than NIO (epoll) on unix systems (which is true)

There is no daragram suppport

Unnecessary threading model (too much abstraction without usage)

4、为什么不用Netty5

1. netty5 中使用了 ForkJoinPool,增加了代码的复杂度,但是对性能的改善却不明显

2. 多个分支的代码同步工作量很大

3. 作者觉得当下还不到发布一个新版本的时候

4. 在发布版本之前,还有更多问题需要调查一下,比如是否应该废弃 exceptionCaught, 是否暴露EventExecutorChooser等等。

二、Hello Netty!

接下来我们就开始从一个简单地demo,进入netty的世界吧。

该demo实现了创建一个Netty服务器和一个netty客户端,服务端接收到客户端请求的时候便打印相应的信息。

1、NettyServer

/**
 * 作者:DarkKing
 * 创建日期:2019/10/02
 * 类说明:netty服务端
 *
 */
public class NettyServer  {

    private final int port;

    public NettyServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) throws InterruptedException {
        int port = 9999;
        NettyServer echoServer = new NettyServer(port);
        System.out.println("服务器启动");
        echoServer.start();
        System.out.println("服务器关闭");
    }

    public void start() throws InterruptedException {
        final NettyServerHandler serverHandler = new NettyServerHandler();
        /*线程组*/
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            /*服务端启动必须*/
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)/*将线程组传入*/
                    .channel(NioServerSocketChannel.class)/*指定使用NIO进行网络传输*/
                    .localAddress(new InetSocketAddress(port))/*指定服务器监听端口*/
                    /*服务端每接收到一个连接请求,就会新启一个socket通信,也就是channel,
                    所以下面这段代码的作用就是为这个子channel增加handle*/
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel ch) throws Exception {
                            /*添加到该子channel的pipeline的尾部*/
                            ch.pipeline().addLast(serverHandler);
                        }
                    });
            ChannelFuture f = b.bind().sync();/*异步绑定到服务器,sync()会阻塞直到完成*/
            f.channel().closeFuture().sync();/*阻塞直到服务器的channel关闭*/

        } finally {
            group.shutdownGracefully().sync();/*优雅关闭线程组*/
        }
    }
}

2、NettyServerHandler

/**
 * 作者:DarkKing
 * 创建日期:2019/10/02
 * 类说明:netty服务端处理handler
 *
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    /*客户端读到数据以后,就会执行*/
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in = (ByteBuf)msg;
        System.out.println("Server accept"+in.toString(CharsetUtil.UTF_8));
        ctx.write(in);

    }
    /*** 服务端读取完成网络数据后的处理*/
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
                .addListener(ChannelFutureListener.CLOSE);
    }
    /*** 发生异常后的处理*/
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

3、NettyClient

public class NettyClient {

    private final int port;
    private final String host;


    public NettyClient(int port, String host) {
        this.port = port;
        this.host = host;
    }

    public void start() throws InterruptedException {
        /*线程组*/
        EventLoopGroup group = new NioEventLoopGroup();
        try{
            /*客户端启动必备*/
            Bootstrap b = new Bootstrap();
            b.group(group)/*把线程组传入*/
                    /*指定使用NIO进行网络传输*/
                    .channel(NioSocketChannel.class)
                    .remoteAddress(new InetSocketAddress(host,port))
                    .handler(new NettyClientHandler());
            /*连接到远程节点,阻塞直到连接完成*/
            ChannelFuture f = b.connect().sync();
            /*阻塞程序,直到Channel发生了关闭*/
            f.channel().closeFuture().sync();
        }finally {
            group.shutdownGracefully().sync();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        new NettyClient(9999,"127.0.0.1").start();
    }
}

4、NettyClientHandler

/**
 * 作者:DarkKing
 * 创建日期:2019/10/02
 * 类说明:netty客户端处理器
 *
 */
public class NettyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    /*客户端读到数据以后,就会执行*/
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg)
            throws Exception {
        System.out.println("client acccept:"+msg.toString(CharsetUtil.UTF_8));
    }

    /*连接建立以后*/
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer(
                "Hello Netty",CharsetUtil.UTF_8));
        //ctx.fireChannelActive();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();

        ctx.close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
    }
}

5、程序演示

1、启动NettyServer,打印服务器启动

2、启动客户端,客户端连接服务器端成功,并发送Hello,Netty!并收到服务器端返回的消息,Hello,Netty!

3、服务器端打印 Server accept:Hello Netty

6、总结

根据上一章网络编程四-原生JDK的NIO及其应用相比,使用Netty大大简化了我们的开发工作量,并将原生JDK复杂的Selector、ByteBuffer、ServerSocketChannel、SocketChannel等组件进行封装。使我们开发者不需要关系具体底层的运行原理和机制。进行模板化的开发。提高开发的效率、以及容错率。

本章主要简单介绍了下Netty的入门。代码已放到github上,GitHub - 379685397/netty: csdn博客代码。下章对Netty的组件进行介绍。

  • 7
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
假设你正在为一个重要的大型公司开发一款全新的任务关键型的应用程序。在第一次会议上,你得知该系统必须要能够扩展到支撑 100000 名并发用户,并且不能有任何的性能损失,这时所有的目光都投向了你。你会怎么说呢? 你可以自信地说:“当然,没问题。”然后留下一顿崇拜的目光离开,回来后悄悄打开netty相关知识,开始编程。 什么是NettyNetty 是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器和客户端。如果你还得去看这些专业术语 那我这文章就毫无意义,接下来我就用大白话告诉你什么是Netty和他的各种组件。 总所周知,Netty是网络编程方面的东西。Netty就是NIO技术的一套框架,就是对NIO技术的封装。有NIO,自然有IO,大白话就是一个是非阻塞IO,一个是阻塞IO。 早期时候的网络编程是阻塞IO模式,IO就是输入输出,举个例子:你打字就是键盘的输入,输入你要打的东西。阻塞就是类似塞车,总是得卡在半路上,等着前面的车开走了我才能开,这里例子中就是电脑总得等着你输入完 我才能把你输入的东西发给别人。那么是什么在等?就是线程! 阻塞IO模式就是一个客户端连接到服务端,服务端就为每个新的客户端 Socket 创建一个新的 Thread。 Netty的书我帮你看!---什么是Netty 什么是Socket?Socket就是你想用Java代码API去组织数据,指定协议去通讯,很烦!写的太多代码!Socket帮你封装了 你只需要调用一下Socket的方法就行了,省事!回到图1-1,你会发现线程开太多了 ,100000人连接我开100000线程吗,还是一直阻塞的等待用户输入,我开的线程还不能去干其他事,那还叫线程吗?太丢人了! 所以Java推出了NIO,Java 对于非阻塞 I/O 的支持是在 2002 年引入的,位于 JDK 1.4 的 java.nio 包中。解决我刚才说的弊端思路就是如下图 Netty的书我帮你看!---什么是Netty class java.nio.channels.Selector 是 Java 的非阻塞 I/O 实现的关键。它使用了事件通知 API 以确定在一组非阻塞套接字中有哪些已经就绪能够进 行 I/O 相关的操作。继续上面的例子,就是当有人输入了 通过Selector 告诉线程说某个Socket有操作,赶紧处理下,这样就不用开那么多线程了,而且所有Socket都没操作的时候,这个线程还能去干别的事,多自由 这就是书本上说的总体来看,与阻塞 I/O 模型相比,这种模型提供了更好的资源管理: 1.使用较少的线程便可以处理许多连接,因此也减少了内存管理和上下文切换所带来开销; 2.当没有 I/O 操作需要处理的时候,线程也可以被用于其他任务。 可当你想使用NIO的时候发现,哇!还是很麻烦!需要记这么多东西,敲这么多代码,这时候Netty就孕育而生了!!在网络编程领域,Netty是Java的卓越框架。它驾驭了Java高级API的能力,并将其隐藏在一 个易于使用的API之后。Netty使你可以专注于自己真正感兴趣的——你的应用程序的独一无二的价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王老狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值