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 ...
随机推荐
- lucene整理3 -- 排序、过滤、分词器
1. 排序 1.1. Sort类 public Sort() public Sort(String field) public Sort(String field,Boolean reverse ...
- DataGridView添加一行数据、全选、取消全选、清空数据、删除选中行
.net 2005下的Windows Form Application,一个DataGridView控件和4个Button,界面设置如下: 代码如下,有注解,相信大家都看得明白: ...
- Kafka与.net core(二)zookeeper
1.zookeeper简单介绍 1.1作用 zookeeper的作用是存储kafka的服务器信息,topic信息,和cunsumer信息.如下图: 而zookeeper是个什么东西呢?简单来说就是一个 ...
- 控制 MediaElement(播放、暂停、停止、音量和速度)
控制 MediaElement(播放.暂停.停止.音量和速度) WPF中对于多媒体的支持非常完整,一般都是通过MediaElement来实现的. http://msdn.microsoft.com/z ...
- LightOJ 1138 Trailing Zeroes (III)(二分 + 思维)
http://lightoj.com/volume_showproblem.php?problem=1138 Trailing Zeroes (III) Time Limit:2000MS M ...
- 使用ubuntu搭建时间机器备份服务
如何在ubuntu下搭建时间备份服务 折腾了很久,终于可以了. 请严格按照下面的方式来操作. 真正明白问题的,可以按照自己的思路来. 我用的是ubnutu 16.04 安装配置netatalk sud ...
- 微信小店调用api代码示例
刚开始调用微信小店api的时候,可能大家会遇到问题.系统总是提示system error,归根结底还是发送的参数不正确. 下面给出几个调用例子: 例子写得不全. <?php function c ...
- django使用haystack来调用Elasticsearch搜索引擎
如何使用django来调用Elasticsearch实现全文的搜索 环境:django ==1.11.11 Haystack为Django提供了模块化的搜索.它的特点是统一的,熟悉的API,可以让你在 ...
- lamp-linux3
LAMP编程之Linux(3) 一.权限管理 1.权限介绍(重点) 在Linux中分别有读.写.执行权限: 读权限: 对于文件夹来说,读权限影响用户是否能够列出目录结构 对于文件来说,读权限影响用户是 ...
- Google 推出新搜索引擎以查找数据集
简评:谷歌推出了一个用于寻找数据集的新搜索引擎,有点厉害! 该工具可以更轻松地访问 Web 上数千个数据存储库中的数百万个数据集,当前还处于测试版: 什么是 Dataset Search? 数 ...