为什么选择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. selenium + PhantomJS 爬取js页面

    from selenium import webdriver import time _url="http://xxxxxxxx.com" driver = webdriver.P ...

  2. Lambda 表达式浅谈- 01

    已经有一段时间没有发布博文了... 今天就写一写lambda的一些简单的使用方法 Lambda 在Msdn 上的描述: Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 ...

  3. Delphi XE7编译安卓程序出错了

    昨天编译一个先前可以正常运行的程序,忽然就不能编译了,总是提示这个错误,经过一番排查,终于搞定了,原因:删除了安卓lib引用的JAR和单元文件.如果你也出现这个问题,打开工程全部目录,看一下是否有打小 ...

  4. IdHTTPServer使用注意问题

    如果在同一电脑上运行多个IdHTTPServer实例,IdHTTPServer使用时候,一定要注意“DefaultPort”属性,其实真正绑定端口是这个属性决定的,所以希望IdHTTPServer绑定 ...

  5. PHP中count()和sizeof()

    php中获取数组长度函数有两个count()和sizeof(),如果传递给这个函数的数组是一个空数组,或者是一个没有经过设定的变量,返回的数组元素个数就是0.两函数功能一样,手册上讲,sizeof() ...

  6. Windows 计划任务之消息提醒

    Windows 计划任务之消息提醒 你肯定也有这种需求.想做一个计划任务,却发现老式消息提醒已经被微软禁止了. 或者就是很单纯的希望给系统弹出一个消息框而并非CMD的echo命令. so...how ...

  7. RHEL安装oracle客户端(版本为11.2)

    RHEL安装oracle客户端(版本为 11.2) 1.获取超级管理员 命令:su - 输入root密码 2.安装依赖包: 命令:yum install -y binutils compat-libs ...

  8. python random 之基础点名器

    import os ,sysimport randomcalled =set() # 创建一个空集合f =open('name.txt ' , 'r')#打开文件读取名字data =f.read()# ...

  9. STM32-RS485通信软硬件实现

    OS:Windows 64 Development kit:MDK5.14 IDE:UV4 MCU:STM32F103C8T6/VET6 AD:Altium Designer 18.0.12 1.RS ...

  10. nginx负载均衡之入门配置

    先来简单了解一下什么是负载均衡,单从字面上的意思来理解就可以解释N台服务器平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况.那么负载均衡的前提就是要有多台服务器才能实现,也就是两台以上 ...