• 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html
  • 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html

网络应用框架Netty快速入门

技术杂谈 勤劳的小蚂蚁 3个月前 (02-05) 66次浏览 已收录 0个评论 扫描二维码

一 初遇Netty

Netty是什么?
Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能、可扩展协议的服务器和客户端。
Netty能做什么?
Netty 是一个 NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器(HTTP服务器,FTP服务器,WebSocket服务器,Redis的Proxy服务器等等)和客户端的协议。Netty 大大简化了网络程序的开发过程比如 TCP 和 UDP 的 socket 服务的开发。
Netty为什么好?
Netty是建立在NIO基础之上,Netty在NIO之上又提供了更高层次的抽象,使用它你可以更容易利用Java NIO提高服务端和客户端的性能。
Netty的特性
1. 设计
  1. 1.1统一的API,适用于不同的协议(阻塞和非阻塞)
  2. 1.2基于可扩展和灵活的事件驱动模型
  3. 1.3高度可定制的线程模型-单线程,一个或多个线程池,如SEDA
  4. 1.4真正的无连接数据报套接字支持(自3.1以来)
2. 性能
  1. 2.1更好的吞吐量,低延迟
  2. 2.2更省资源
  3. 2.3尽量减少不必要的内存拷贝
3. 安全
  1. 完整的SSL / TLSStartTLS协议的支持
4. 易用性
  1. 4.1官方有详细的使用指南
  2. 4.2对环境要求很低
NIO和IO的区别是什么?
1. 一个面向字节一个面向缓冲;
IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
2. NIO是非阻塞IO,IO是阻塞IO
阻塞意味着当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入,该线程在此期间不能再干任何事情了。而非阻塞不会这样。

二 Netty使用

环境要求:
  • JDK 7+
  • Maven 3.2.x
  • Netty 4.x
Maven依赖:
  1.        <dependency>
  2.            <groupId>io.netty</groupId>
  3.            <artifactId>netty-all</artifactId>
  4.            <version>4.0.32.Final</version>
  5.        </dependency>
以下Netty examples来源: 官方文档

2.1 写个抛弃服务器

DiscardServerHandler.java
  1. import io.netty.buffer.ByteBuf;
  2. import io.netty.channel.ChannelHandlerContext;
  3. import io.netty.channel.ChannelInboundHandlerAdapter;
  4. /**
  5. * handler 是由 Netty 生成用来处理 I/O 事件的。
  6. */
  7. publicclassDiscardServerHandlerextendsChannelInboundHandlerAdapter{// (1)
  8.    /**
  9.     * 这里我们覆盖了 chanelRead() 事件处理方法。
  10.     * 每当从客户端收到新的数据时,这个方法会在收到消息时被调用。
  11.     *((ByteBuf) msg).release():丢弃数据
  12.     */
  13.    @Override
  14.    publicvoid channelRead(ChannelHandlerContext ctx,Object msg){// (2)
  15.        // 默默地丢弃收到的数据
  16.        ((ByteBuf) msg).release();// (3)
  17.    }
  18.    @Override
  19.    publicvoid exceptionCaught(ChannelHandlerContext ctx,Throwable cause){// (4)
  20.        // 当出现异常就关闭连接
  21.        cause.printStackTrace();
  22.        ctx.close();
  23.    }
  24. }
目前我们已经实现了 DISCARD 服务器的一半功能,剩下的需要编写一个 main() 方法来启动服务端的 DiscardServerHandler。
DiscardServer.java
  1. import io.netty.bootstrap.ServerBootstrap;
  2. import io.netty.channel.ChannelFuture;
  3. import io.netty.channel.ChannelInitializer;
  4. import io.netty.channel.ChannelOption;
  5. import io.netty.channel.EventLoopGroup;
  6. import io.netty.channel.nio.NioEventLoopGroup;
  7. import io.netty.channel.socket.SocketChannel;
  8. import io.netty.channel.socket.nio.NioServerSocketChannel;
  9. /**
  10. * 启动服务端的 DiscardServerHandler
  11. */
  12. publicclassDiscardServer{
  13.    privateint port;
  14.    publicDiscardServer(int port){
  15.        this.port = port;
  16.    }
  17.    publicvoid run()throwsException{
  18.        //在这个例子中我们实现了一个服务端的应用,因此会有2个 NioEventLoopGroup 会被使用。
  19.        //第一个经常被叫做‘boss’,用来接收进来的连接。
  20.        //第二个经常被叫做‘worker’,用来处理已经被接收的连接,一旦‘boss’接收到连接,就会把连接信息注册到‘worker’上。
  21.        EventLoopGroup bossGroup =newNioEventLoopGroup();
  22.        EventLoopGroup workerGroup =newNioEventLoopGroup();
  23.        try{
  24.            //启动 NIO 服务的辅助启动类
  25.            ServerBootstrap serverBootstrap =newServerBootstrap();
  26.            //用于处理ServerChannel和Channel的所有事件和IO。
  27.            serverBootstrap.group(bossGroup, workerGroup)
  28.             .channel(NioServerSocketChannel.class)// (3)
  29.             .childHandler(newChannelInitializer<SocketChannel>(){// (4)
  30.                 @Override
  31.                 publicvoid initChannel(SocketChannel ch)throwsException{
  32.                     ch.pipeline().addLast(newDiscardServerHandler());
  33.                 }
  34.             })
  35.             .option(ChannelOption.SO_BACKLOG,128)          // (5)
  36.             .childOption(ChannelOption.SO_KEEPALIVE,true);// (6)
  37.            // 绑定端口,开始接收进来的连接
  38.            ChannelFuture f = serverBootstrap.bind(port).sync();// (7)
  39.            // 等待服务器  socket 关闭 。
  40.            // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
  41.            f.channel().closeFuture().sync();
  42.        }finally{
  43.            workerGroup.shutdownGracefully();
  44.            bossGroup.shutdownGracefully();
  45.        }
  46.    }
  47.    publicstaticvoid main(String[] args)throwsException{
  48.        int port;
  49.        if(args.length >0){
  50.            port =Integer.parseInt(args[0]);
  51.        }else{
  52.            port =8080;
  53.        }
  54.        newDiscardServer(port).run();
  55.    }
  56. }

2.2 查看收到的数据

我们刚刚已经编写出我们第一个服务端,我们需要测试一下他是否真的可以运行。最简单的测试方法是用 telnet 命令。例如,你可以在命令行上输入telnet localhost 8080 或者其他类型参数。
然而我们能说这个服务端是正常运行了吗?事实上我们也不知道,因为他是一个 discard 服务,你根本不可能得到任何的响应。为了证明他仍然是在正常工作的,让我们修改服务端的程序来打印出他到底接收到了什么。
我们已经知道 channelRead() 方法是在数据被接收的时候调用。让我们放一些代码到 DiscardServerHandler 类的 channelRead() 方法。
修改DiscardServerHandler类的channelRead(ChannelHandlerContext ctx, Object msg)方法如下:
  1. @Override
  2. publicvoid channelRead(ChannelHandlerContext ctx,Object msg){
  3.    ByteBuf in =(ByteBuf) msg;
  4.    try{
  5.        while(in.isReadable()){// (1)
  6.            System.out.print((char) in.readByte());
  7.            System.out.flush();
  8.        }
  9.    }finally{
  10.        ReferenceCountUtil.release(msg);// (2)
  11.    }
  12. }
再次验证,cmd下输入:telnet localhost 8080。你将会看到服务端打印出了他所接收到的消息。
如下:
你在dos界面输入的消息会被显示出来

2.3 写个应答服务器

到目前为止,我们虽然接收到了数据,但没有做任何的响应。然而一个服务端通常会对一个请求作出响应。让我们学习怎样在 ECHO 协议的实现下编写一个响应消息给客户端,这个协议针对任何接收的数据都会返回一个响应。
和 discard server 唯一不同的是把在此之前我们实现的 channelRead() 方法,返回所有的数据替代打印接收数据到控制台上的逻辑。因此,需要把 channelRead() 方法修改如下:
  1.    @Override
  2.    publicvoid channelRead(ChannelHandlerContext ctx,Object msg){
  3.        ctx.write(msg);
  4.        ctx.flush();
  5.    }
再次验证,cmd下输入:telnet localhost 8080。你会看到服务端会发回一个你已经发送的消息。如下:

    丨极客文库, 版权所有丨如未注明 , 均为原创丨
    本网站采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行授权
    转载请注明原文链接:网络应用框架Netty快速入门
    喜欢 (0)
    [247507792@qq.com]
    分享 (0)
    勤劳的小蚂蚁
    关于作者:
    温馨提示:本文来源于网络,转载文章皆标明了出处,如果您发现侵权文章,请及时向站长反馈删除。

    您必须 登录 才能发表评论!

    • 精品技术教程
    • 编程资源分享
    • 问答交流社区
    • 极客文库知识库

    客服QQ


    QQ:2248886839


    工作时间:09:00-23:00