为什么选择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. Npoi将excel数据导入到sqlserver数据库

    /// <summary> /// 将excel导入到datatable /// </summary> /// <param name="filePath&qu ...

  2. ASP.NET MVC 防止CSRF攻击

    简介 MVC中的Html.AntiForgeryToken()是用来防止跨站请求伪造(CSRF:Cross-site request forgery)攻击的一个措施,它跟XSS(XSS又叫CSS:Cr ...

  3. 「ZJOI 2010」 排列计数

    题目链接 戳我 \(Solution\) 其实我们可以发现这题等价于让你求: 用\(1\)~\(n\)的数组成一个完全二叉树使之满足小根堆性质的方案数 于是我们可以考虑\(dp\) 假设我们现在在\( ...

  4. django系列5.3--ORM数据库的多表操作

    首先来创建一个模型,数据库的关系就清楚了 models.py from django.db import models # Create your models here. class Author( ...

  5. BEAUTIFUL

    DESCRIPTION:一个长度为n 的序列,对于每个位置i 的数ai 都有一个优美值,其定义是:找到序列中最长的一段[l, r],满足l<i<r,且[l, r] 中位数为ai(我们比较序 ...

  6. 深入了解java虚拟机(JVM) 第十章 字节码指令

    一.字节码指令的含义 Java字节码指令由一个字节长度的,代表某种特定操作含义的数字(操作码)以及其后的零至多个代表此操作所需参数(操作数).此外字节码指令是面向操作数栈的,这里操作数栈在功能上对应实 ...

  7. “全栈2019”Java第一百零一章:局部内部类覆盖作用域内成员详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. java中二维数组遍历

    public class Demoshuzu2 { public static void main(String[] args) {        int[][] arr2 = {{78,79,65, ...

  9. mysql 赋给用户远程权限 grant all privileges on

    我配置了权限 就可以在Windows下访问我虚拟机中的数据库了 来源:http://blog.csdn.net/louisliaoxh/article/details/52767209 登录: 在本机 ...

  10. AngularJS源码解析3:RootScope的创建过程

    RootScopeProvider简介 RootScopeProvider是angularjs里面比较活跃的一个provider.它主要用来生成实例rootScope,它代表angularjs应用的根 ...