为什么选择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程序的更多相关文章

  1. 【Netty】第一个Netty应用

    一.前言 前面已经学习完了Java NIO的内容,接着来学习Netty,本篇将通过一个简单的应用来了解Netty的使用. 二.Netty应用 2.1 服务端客户端框架图 下图展示了Netty中服务端与 ...

  2. netty(二) 创建一个netty服务端和客户端

    服务端 NettyServer package com.zw.netty.config; import com.zw.netty.channel.ServerInitializer;import io ...

  3. Netty4具体解释二:开发第一个Netty应用程序

        既然是入门,那我们就在这里写一个简单的Demo,client发送一个字符串到server端,server端接收字符串后再发送回client. 2.1.配置开发环境 1.安装JDK 2.去官网下 ...

  4. Netty入门二:开发第一个Netty应用程序

    Netty入门二:开发第一个Netty应用程序 时间 2014-05-07 18:25:43  CSDN博客 原文  http://blog.csdn.net/suifeng3051/article/ ...

  5. 构建基于Netty 的HTTP/HTTPS 应用程序

    HTTP/HTTPS是最常见的协议套件之一,并且随着智能手机的成功,它的应用也日益广泛,因为对于任何公司来说,拥有一个可以被移动设备访问的网站几乎是必须的.这些协议也被用于其他方面.许多组织导出的用于 ...

  6. Netty(一)——Netty入门程序

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7447618.html 有兴趣的可先了解下:4种I/O的对比与选型 主要内容包括: Netty开发环境的搭建 ...

  7. 「Netty实战 02」手把手教你实现自己的第一个 Netty 应用!新手也能搞懂!

    大家好,我是 「后端技术进阶」 作者,一个热爱技术的少年. 很多小伙伴搞不清楚为啥要学习 Netty ,今天这篇文章开始之前,简单说一下自己的看法: @ 目录 服务端 创建服务端 自定义服务端 Cha ...

  8. Netty 框架学习 —— 基于 Netty 的 HTTP/HTTPS 应用程序

    通过 SSL/TLS 保护应用程序 SSL 和 TLS 安全协议层叠在其他协议之上,用以实现数据安全.为了支持 SSL/TLS,Java 提供了 javax.net.ssl 包,它的 SSLConte ...

  9. Netty实现的一个异步Socket代码

    本人写的一个使用Netty实现的一个异步Socket代码 package test.core.nio; import com.google.common.util.concurrent.ThreadF ...

随机推荐

  1. 数据库工具SQLite Expert Personal的简单使用

    官方网站: sqliteexpert官方网址 - SQLite administration | SQLite Expert 先使用SQLite Expert Personal熟悉SQLite语句 插 ...

  2. 【C#】在datatable中添加一序号列,编号从1依次递增,并且在第一列

    详细链接:https://shop499704308.taobao.com/?spm=a1z38n.10677092.card.11.594c1debsAGeak/// <summary> ...

  3. Cookie客户端缓存.Session.Application

    Cookie客户端缓存. 1.引言 随着浏览器的处理能力不断增强,越来越多的网站开始考虑将数据存储在「客户端」,那么久不得不谈本地存储了. 本地存储的好处: 一是避免取回数据前页面一片空白,如果不需要 ...

  4. linux 动态库加载路径修改

    1.在 /etc/ld.so.conf 文件中添加搜索路径,重启或者 ldconfig 生效: 2.在 /etc/ld.so.conf.d 目录下添加 *.conf 文件,其中可以添加搜索路径,重启获 ...

  5. shell、cmd、dos和脚本语言区别和联系

    问题一:DOS与windows中cmd区别   在windows系统中,“开始-运行-cmd”可以打开“cmd.exe”,进行命令行操作. 操作系统可以分成核心(kernel)和Shell(外壳)两部 ...

  6. springmvc 通过@ResponseBody 返回json的中文乱码解决方案2个

    1.方法上面的RequestMapping要加上红色的部分.   @ResponseBody     @RequestMapping(value = "/search", prod ...

  7. C#取得控制台应用程序的根目录方法

    如有雷同,不胜荣幸,若转载,请注明 取得控制台应用程序的根目录方法1:Environment.CurrentDirectory 取得或设置当前工作目录的完整限定路径2:AppDomain.Curren ...

  8. windows文件名太长无法删除的解决办法

    安装nodejs 的模块hexo后,由于香重新安装,在删除的时候却提示文件名太长无法删除,dos命令.回收站各种都无法搞定,后来找到解决办法: 1.进入这些文件的所在目录的上层目录,右键这些文件的所在 ...

  9. elasticsearch-analysis-pinyin

    来源:https://github.com/medcl/elasticsearch-analysis-pinyin Pinyin Analysis for Elasticsearch This Pin ...

  10. 2016级算法期末上机-B.简单·ModricWang's Fight with DDLs I

    1124 ModricWang's Fight with DDLs I 思路 这道题本质上就是一个多项式求值,题目中的n需要手动算一下,单位复根可以根据复数的性质来求,即\(e^{i\pi}+1=0\ ...