Netty(1):第一个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来实现一个时钟的小程序,服务器端接收特定的指令然后将服务器时间返回给客户端,客户端按照一定的时间间隔往服务器端发送命令。
package com.rampage.netty.time; 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; /**
* 时钟程序的服务器端
* @author zyq
*
*/
public class TimeServer { public static void main(String[] args) throws Exception {
new TimeServer().bind(8080);
} public void bind(int port) throws Exception {
// 配置服务器的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup(); try {
ServerBootstrap bootStrap = new ServerBootstrap(); // 进行链式调用(每一次调用的返回结果都是ServerBootstrap)
// group带两个参数第一个表示给父(acceptor)用的EventExecutorGroup(其实就是线程池)
// 第二个参数表示子(client)线程池
// channel方法可以带一个ServerChannel类来创建进行IO操作的通道。
// option方法给Channel定制对应的选项
// childHandler方法用来处理Channel中的请求
bootStrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChildChannelHandler()); // 绑定端口,等待同步成功
// bind方法返回一个ChannelFuture类,就是相当于绑定端口并且创建一个新的channel
// sync方法会等待ChannelFuture的处理结束
ChannelFuture future = bootStrap.bind(port).sync(); // 等待服务器监听端口关闭
future.channel().closeFuture().sync();
} finally {
// 优雅地退出,释放线程资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
} private class ChildChannelHandler extends ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel arg0) throws Exception {
arg0.pipeline().addLast(new TimeServerHandler());
} }
}
TimeServer
package com.rampage.netty.time; import java.util.Date; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; /**
* 时间服务器的处理类,只有netty5中的ChannelHandlerAdapter中才有ChannelRead和ChannelReadComplete方法。
* @author zyq
*
*/
public class TimeServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// netty中的ByteBuf类相当于jdk中的ByteBuffer类,但是功能更加强大
ByteBuf buf = (ByteBuf) msg; // readableBytes返回缓冲区可读的字节数
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()); // 为了防止频繁唤醒Selector进行消息发送,Netty的write方法并不直接将消息写入到SocketChannel中,而是把消息放入到缓冲数组
ctx.write(resp);
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// 将放到缓冲数组中的消息写入到SocketChannel中去
ctx.flush();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
} }
TimeServerHandler
package com.rampage.netty.time; 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; /**
* 时钟程序的客户端
* @author zyq
*
*/
public class TimeClient { public static void main(String[] args) throws Exception {
new TimeClient().connect("127.0.0.1", 8080);
} public void connect(String host, int port) throws Exception {
// 配置客户端NIO线程池
EventLoopGroup group = new NioEventLoopGroup(); Bootstrap strap = new Bootstrap();
try {
// 这里用了匿名内部类,各个函数的含义同Server端
strap.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() { @Override
protected void initChannel(SocketChannel arg0) throws Exception {
arg0.pipeline().addLast(new TimeClientHandler());
} }); // 发起异步连接操作
ChannelFuture future = strap.connect(host, port).sync(); // 等待客户端关闭(注意调用的是closeFuture如果直接调用close会立马关闭)
future.channel().closeFuture().sync();
} finally {
// 优雅的关闭
group.shutdownGracefully();
}
}
}
TimeClient
package com.rampage.netty.time; import java.util.logging.Logger; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; public class TimeClientHandler extends ChannelHandlerAdapter { private static final Logger LOGGER = Logger.getLogger(TimeClientHandler.class.getName()); private final ByteBuf firstMsg; public TimeClientHandler() {
byte[] req = "QUERY TIME ORDER".getBytes();
firstMsg = Unpooled.buffer(req.length);
firstMsg.writeBytes(req);
} /**
* channel连通之后的处理
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(firstMsg);
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
byte[] resp = new byte[buf.readableBytes()];
buf.readBytes(resp); String body = new String(resp, "UTF-8");
System.out.println("Now is:" + body); // 两秒钟后继续向服务器端发送消息
Thread.sleep(2000);
byte[] req = "QUERY TIME ORDER".getBytes();
ByteBuf sendMsg = Unpooled.buffer(req.length);
sendMsg.writeBytes(req);
ctx.writeAndFlush(sendMsg);
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
LOGGER.warning("Unexpected exception from downstream:" + cause.getMessage());
ctx.close();
} }
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(1):第一个netty程序的更多相关文章
- 【Netty】第一个Netty应用
一.前言 前面已经学习完了Java NIO的内容,接着来学习Netty,本篇将通过一个简单的应用来了解Netty的使用. 二.Netty应用 2.1 服务端客户端框架图 下图展示了Netty中服务端与 ...
- netty(二) 创建一个netty服务端和客户端
服务端 NettyServer package com.zw.netty.config; import com.zw.netty.channel.ServerInitializer;import io ...
- Netty4具体解释二:开发第一个Netty应用程序
既然是入门,那我们就在这里写一个简单的Demo,client发送一个字符串到server端,server端接收字符串后再发送回client. 2.1.配置开发环境 1.安装JDK 2.去官网下 ...
- Netty入门二:开发第一个Netty应用程序
Netty入门二:开发第一个Netty应用程序 时间 2014-05-07 18:25:43 CSDN博客 原文 http://blog.csdn.net/suifeng3051/article/ ...
- 构建基于Netty 的HTTP/HTTPS 应用程序
HTTP/HTTPS是最常见的协议套件之一,并且随着智能手机的成功,它的应用也日益广泛,因为对于任何公司来说,拥有一个可以被移动设备访问的网站几乎是必须的.这些协议也被用于其他方面.许多组织导出的用于 ...
- Netty(一)——Netty入门程序
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7447618.html 有兴趣的可先了解下:4种I/O的对比与选型 主要内容包括: Netty开发环境的搭建 ...
- 「Netty实战 02」手把手教你实现自己的第一个 Netty 应用!新手也能搞懂!
大家好,我是 「后端技术进阶」 作者,一个热爱技术的少年. 很多小伙伴搞不清楚为啥要学习 Netty ,今天这篇文章开始之前,简单说一下自己的看法: @ 目录 服务端 创建服务端 自定义服务端 Cha ...
- Netty 框架学习 —— 基于 Netty 的 HTTP/HTTPS 应用程序
通过 SSL/TLS 保护应用程序 SSL 和 TLS 安全协议层叠在其他协议之上,用以实现数据安全.为了支持 SSL/TLS,Java 提供了 javax.net.ssl 包,它的 SSLConte ...
- Netty实现的一个异步Socket代码
本人写的一个使用Netty实现的一个异步Socket代码 package test.core.nio; import com.google.common.util.concurrent.ThreadF ...
随机推荐
- C语言/C++编程学习:和QT零距离接触的意义
C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...
- [uwp]自定义Behavior之随意拖动
由于最近有需求,所以自定义了一个随意拖动元素的Behavior. 当然在使用这个自定义的Behavior时,有个小假设:拖动元素必须是Canvas容器的子元素. 实现原理比较简单低效: 监听被拖动元素 ...
- 细节之strcat
写代码也这么多年了,有些非常基础的东西却让我差点栽跟头: 有如下一种场景的需求代码: char tmp; ]; memset(input, , ); ) // ptr是得到了某块全局内存的 { tmp ...
- iOS 错误:… is being deallocated while key value observing are still registered with it
这个错误从字面上来看就是有一个实例由于被observing而无法被释放. 具体原因可能是该对象添加了一个oberver.所以释放的时候要先取消observer. 具体方法是在 dealloc 方法中: ...
- Exp4 恶意代码分析 20164323段钊阳
网络对抗技术 20164323 Exp4 恶意代码分析 1.如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些,用什么方法来监控. ...
- A - 确定比赛名次(拓扑)
点击打开链接 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比 ...
- 【OCP|052】OCP最新题库解析系列-2
2.Which two are true about Optimizer Statistics? ❑ A) They do not persist across Instance restarts. ...
- 在macro中怎么接着使用一些库?(遇到的例子:current_user)
这回是用的stackoverflow http://stackoverflow.com/questions/26339583/ 在调用模板html的时候 写上一个 with context 整体效果 ...
- Android-获取手机已经安装的程序
有时候我们会查询手机里面是否安装了某个程序,或者获取已经安装软件名称的集合. android这边提供了相应的接口. [java] view plaincopy final PackageManager ...
- IOS----UIScrollerView的使用
刚刚遛狗回来,前段时间创建的这篇博客一直没有填充内容,今天把scrollerview正好整理一下. 1.scrollerview的主要作用:当界面显示不开要显示的内容,scrollerview提供了滑 ...