开发者社区> 槟城码农> 正文

Netty(1):第一个netty程序

简介: 为什么选择Netty   netty是业界最流行的NIO框架之一,它的健壮型,功能,性能,可定制性和可扩展性都是首屈一指的,Hadoop的RPC框架Avro就使用了netty作为底层的通信框架,此外netty在互联网,大数据,网络游戏,企业应用,电信软件等众多行业都得到了成功的商业应用。
+关注继续查看

为什么选择Netty

  netty是业界最流行的NIO框架之一,它的健壮型,功能,性能,可定制性和可扩展性都是首屈一指的,Hadoop的RPC框架Avro就使用了netty作为底层的通信框架,此外netty在互联网,大数据,网络游戏,企业应用,电信软件等众多行业都得到了成功的商业应用。正因为以上的一些特性,使得netty已经成为java NIO编程的首选框架。

 

构建netty开发环境

  其实使用netty很简单,直接将其jar包引入到工程中即可使用。 去 http://netty.io/网站上下载最新版本的jar包(由于官网上netty5已经被废弃,但是这里仍然使用netty5进行开发, 可以考虑从csnd下载),我这里下载的为:netty-5.0.0.Alpha1.tar.bz2。这其实是一个压缩文件,解压这个文件,取里面的所有类集合到一起的那个jar包netty-all-5.0.0.Alpha1.jar即可。另外还需要注意的是,我这里使用的jdk版本是1.8。

 

第一个netty程序
  这里利用netty来实现一个时钟的小程序,服务器端接收特定的指令然后将服务器时间返回给客户端,客户端按照一定的时间间隔往服务器端发送命令。

 1 package com.rampage.netty.time;
 2 
 3 import io.netty.bootstrap.ServerBootstrap;
 4 import io.netty.channel.ChannelFuture;
 5 import io.netty.channel.ChannelInitializer;
 6 import io.netty.channel.ChannelOption;
 7 import io.netty.channel.EventLoopGroup;
 8 import io.netty.channel.nio.NioEventLoopGroup;
 9 import io.netty.channel.socket.SocketChannel;
10 import io.netty.channel.socket.nio.NioServerSocketChannel;
11 
12 /**
13  * 时钟程序的服务器端
14  * @author zyq
15  *
16  */
17 public class TimeServer {
18     
19     public static void main(String[] args) throws Exception {
20         new TimeServer().bind(8080);
21     }
22     
23     public void bind(int port) throws Exception {
24         // 配置服务器的NIO线程组
25         EventLoopGroup bossGroup = new NioEventLoopGroup();
26         EventLoopGroup workerGroup = new NioEventLoopGroup();
27         
28         try {
29             ServerBootstrap bootStrap = new ServerBootstrap();
30             
31             // 进行链式调用(每一次调用的返回结果都是ServerBootstrap)
32             // group带两个参数第一个表示给父(acceptor)用的EventExecutorGroup(其实就是线程池)
33             // 第二个参数表示子(client)线程池
34             // channel方法可以带一个ServerChannel类来创建进行IO操作的通道。
35             // option方法给Channel定制对应的选项
36             // childHandler方法用来处理Channel中的请求
37             bootStrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
38             .option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChildChannelHandler());
39             
40             // 绑定端口,等待同步成功
41             // bind方法返回一个ChannelFuture类,就是相当于绑定端口并且创建一个新的channel
42             // sync方法会等待ChannelFuture的处理结束
43             ChannelFuture future = bootStrap.bind(port).sync();
44             
45             // 等待服务器监听端口关闭
46             future.channel().closeFuture().sync();
47         } finally {
48             // 优雅地退出,释放线程资源
49             bossGroup.shutdownGracefully();
50             workerGroup.shutdownGracefully();
51         }
52     }
53     
54     private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
55 
56         @Override
57         protected void initChannel(SocketChannel arg0) throws Exception {
58             arg0.pipeline().addLast(new TimeServerHandler());
59         }
60         
61     }
62 }
TimeServer
 1 package com.rampage.netty.time;
 2 
 3 import java.util.Date;
 4 
 5 import io.netty.buffer.ByteBuf;
 6 import io.netty.buffer.Unpooled;
 7 import io.netty.channel.ChannelHandlerAdapter;
 8 import io.netty.channel.ChannelHandlerContext;
 9 
10 /**
11  * 时间服务器的处理类,只有netty5中的ChannelHandlerAdapter中才有ChannelRead和ChannelReadComplete方法。
12  * @author zyq
13  *
14  */
15 public class TimeServerHandler extends ChannelHandlerAdapter {
16     @Override 
17     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
18         // netty中的ByteBuf类相当于jdk中的ByteBuffer类,但是功能更加强大
19         ByteBuf buf = (ByteBuf) msg;
20         
21         // readableBytes返回缓冲区可读的字节数
22         byte[] req = new byte[buf.readableBytes()];
23         
24         // 将缓冲区的字节数复制到新的字节数组中去
25         buf.readBytes(req);
26         
27         // 根据客户端传来的信息得到应答信息
28         String body = new String(req, "UTF-8");
29         System.out.println("The time server receive order:" + body);
30         String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
31         
32         // 给客户端的回应
33         ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
34         
35         // 为了防止频繁唤醒Selector进行消息发送,Netty的write方法并不直接将消息写入到SocketChannel中,而是把消息放入到缓冲数组
36         ctx.write(resp);
37     }
38 
39     @Override
40     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
41         // 将放到缓冲数组中的消息写入到SocketChannel中去
42         ctx.flush();
43     }
44 
45     @Override
46     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
47         ctx.close();
48     }
49     
50     
51 }
TimeServerHandler
 1 package com.rampage.netty.time;
 2 
 3 import io.netty.bootstrap.Bootstrap;
 4 import io.netty.channel.ChannelFuture;
 5 import io.netty.channel.ChannelInitializer;
 6 import io.netty.channel.ChannelOption;
 7 import io.netty.channel.EventLoopGroup;
 8 import io.netty.channel.nio.NioEventLoopGroup;
 9 import io.netty.channel.socket.SocketChannel;
10 import io.netty.channel.socket.nio.NioSocketChannel;
11 
12 /**
13  * 时钟程序的客户端
14  * @author zyq
15  *
16  */
17 public class TimeClient {
18     
19     public static void main(String[] args) throws Exception {
20         new TimeClient().connect("127.0.0.1", 8080);
21     }
22     
23     public void connect(String host, int port) throws Exception {
24         // 配置客户端NIO线程池
25         EventLoopGroup group = new NioEventLoopGroup();
26         
27         Bootstrap strap = new Bootstrap();
28         try {
29             // 这里用了匿名内部类,各个函数的含义同Server端
30             strap.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
31             .handler(new ChannelInitializer<SocketChannel>() {
32 
33                 @Override
34                 protected void initChannel(SocketChannel arg0) throws Exception {
35                     arg0.pipeline().addLast(new TimeClientHandler());
36                 }
37                 
38             });
39             
40             // 发起异步连接操作
41             ChannelFuture future = strap.connect(host, port).sync();
42             
43             // 等待客户端关闭(注意调用的是closeFuture如果直接调用close会立马关闭)
44             future.channel().closeFuture().sync();
45         } finally {
46             // 优雅的关闭
47             group.shutdownGracefully();
48         }
49     }
50 }
TimeClient
 1 package com.rampage.netty.time;
 2 
 3 import java.util.logging.Logger;
 4 
 5 import io.netty.buffer.ByteBuf;
 6 import io.netty.buffer.Unpooled;
 7 import io.netty.channel.ChannelHandlerAdapter;
 8 import io.netty.channel.ChannelHandlerContext;
 9 
10 public class TimeClientHandler extends ChannelHandlerAdapter {
11 
12     private static final Logger LOGGER = Logger.getLogger(TimeClientHandler.class.getName());
13     
14     private final ByteBuf firstMsg;
15     
16     public TimeClientHandler() {
17         byte[] req = "QUERY TIME ORDER".getBytes();
18         firstMsg = Unpooled.buffer(req.length);
19         firstMsg.writeBytes(req);
20     }
21     
22     /**
23      * channel连通之后的处理
24      */
25     @Override
26     public void channelActive(ChannelHandlerContext ctx) throws Exception {
27         ctx.writeAndFlush(firstMsg);
28     }
29     
30     @Override
31     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
32         ByteBuf buf = (ByteBuf) msg;
33         byte[] resp = new byte[buf.readableBytes()];
34         buf.readBytes(resp);
35         
36         String body = new String(resp, "UTF-8");
37         System.out.println("Now is:" + body);
38         
39         // 两秒钟后继续向服务器端发送消息
40         Thread.sleep(2000);
41         byte[] req = "QUERY TIME ORDER".getBytes();
42         ByteBuf sendMsg = Unpooled.buffer(req.length);
43         sendMsg.writeBytes(req);
44         ctx.writeAndFlush(sendMsg);
45     }
46 
47     @Override
48     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
49         LOGGER.warning("Unexpected exception from downstream:" + cause.getMessage());
50         ctx.close();
51     }
52 
53     
54 }
TimeClientHandler

服务器端的运行结果如下:

The time server receive order:QUERY TIME ORDER
The time server receive order:QUERY TIME ORDER
The time server receive order:QUERY TIME ORDER
The time server receive order:QUERY TIME ORDER

...

客户端的运行结果如下:

Now is:Wed Aug 03 05:55:30 PDT 2016
Now is:Wed Aug 03 05:55:33 PDT 2016
Now is:Wed Aug 03 05:55:35 PDT 2016
Now is:Wed Aug 03 05:55:37 PDT 2016

...

 

可以发现通过Netty框架来实现NIO极大的简化了编码和维护难度。代码调理更加清晰。

TimeClientHandler

黎明前最黑暗,成功前最绝望!

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
使用Netty构建高性能的网络应用程序
使用Netty构建高性能的网络应用程序
40 0
Netty In Action中文版 - 第二章:第一个Netty程序
Netty In Action中文版 - 第二章第一个Netty程序 本章介绍 获取Netty4最新版本 设置运行环境来构建和运行netty程序 创建一个基于Netty的服务器和客户端 拦截和处理异常 编写和运行Netty服务器和客户端 本章将简单介绍Netty的核心概念这个狠心概念就是学习Netty是如何拦截和处理异常对于刚开始学习netty的读者利用netty的异常拦截机制来调试程序问题很有帮助。
1500 0
netty入门小程序
Netty的特性 设计统一的API,适用于不同的协议(阻塞和非阻塞)基于灵活、可扩展的事件驱动模型高度可定制的线程模型可靠的无连接数据Socket支持(UDP) 性能更好的吞吐量,低延迟更省资源尽量减少不必要的内存拷贝 安全完整的SSL/TLS和STARTTLS的支持能在Applet与Android的限制环境运行良好 健壮性不再因过快、过慢或超负载连接导致OutOfMem
2334 0
牛皮了!华为18级专家一文带你精通NIO、Netty、Redis和Zookeeper
上文给大家分享的是多线程,锁,JMM,JUC和高并发设计模式的知识点内容,想要看的小伙伴可以点击这里,文章链接:一篇神文就把java多线程,锁,JMM,JUC和高并发设计模式讲明白了。
44 0
即时通讯技术文集(第9期):Java NIO和Netty入门系列 [共19篇]
为了更好地分类阅读52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第9 期。
105 0
【Netty】Java NIO 基础
Netty本质是一个NIO框架,适用于服务器通讯相关的多种应用场景。 Netty作为一款基于Java开发的高性能网络框架,想要从认识到熟悉再到掌握最终理解,因此我们需要从最基础的NIO开始学习。如果你已经学习并掌握了NIO相关知识,那么可以直接进入Netty相关文章的学习;如果没有了解过也没有关系,那我们就从当前文章开始学习吧!🎉🎉🎉
130 0
Netty源码分析之NIO
Socket是两台主机之间逻辑连接的端点。TCP/IP是传输层协议,定义数据如何在忘了中进行传输。HTTP是应用成协议,主要用来定义规范,包装数据,方便数据处理。Socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。
77 0
Netty实战与源码剖析(二)——基于NIO的群聊系统
Netty实战与源码剖析(二)——基于NIO的群聊系统
98 0
Netty实战与源码剖析(一)——浅谈NIO编程
Netty实战与源码剖析(一)——浅谈NIO编程
139 0
02、Netty学习笔记—(NIO网络编程和IO模型)(二)
02、Netty学习笔记—(NIO网络编程和IO模型)(二)
114 0
+关注
槟城码农
文章
问答
视频
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载