3.1 Netty开发环境的搭建

  3.1.1 下载Netty的软件包

  3.1.2 搭建Netty应用工程

3.2 Netty服务端开发

3.3 Netty客户端开发

3.4 运行和调试

  3.4.1 服务端和客户端的运行

  3.4.2 打包和部署

3.5 总结

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    3.1 Netty开发环境的搭建

      3.1.1 下载Netty的软件包

     <!-- netty -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>

      3.1.2 搭建Netty应用工程

    3.2 Netty服务端开发

      回顾使用JDK的NIO类库进行服务端开发的步骤:

      ① 创建ServerSocketChannel,配置它为非阻塞模式;

      ② 绑定监听,配置TCP参数,例如backlog大小;

      ③ 创建一个独立的I/O线程,用于轮询多路复用器Selector;

      ④ 创建Selector,将之前创建的ServerSocketChannel注册到Selector上,监听SelectionKey.ACCEPT;

      ⑤ 启动I/O线程,喜爱循环体中执行Selector.select()方法,轮询就绪的Channel;

      ⑥ 当轮询到了处于就绪状态的Channel时,需要对其进行判断,如果是OP_ACCEPT状态,说明是新的客户端接入,则调用ServerSocketChannel.accept()方法接受新的客户端;

      ⑦ 设置新接入的客户端链路SocketChannel为非阻塞模式,配置其他的一些TCP参数;

      ⑧ 将SocketChannel注册到Selector,监听OP_READ操作位;

      ⑨ 如果轮询的Channel为OP_READ,则说明SocketChannel中有新的就绪的数据包需要读取,则构造ByteBuffer对象,读取数据包。

      ⑩ 如果轮询的Channel为OP_WRITE,则说明还有数据没有发送完成,需要继续发送。

      使用Netty进行服务端的开发:

        Class : TimeServer

package com.phei.netty.chap3;

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; import org.springframework.util.StringUtils; public class TimeServer { public void bind(int port) throws Exception{
// 配置服务端的NIO线程组
// 创建两个NioEventLoopGroup实例。
// NioEventLoopGroup是个线程组,包含了一组NIO线程,专门用于网络事件的处理,实际上它们就是Reactor线程组。
// 一个用于服务端接收客户端的连接,一个用于进行SocketChannel的网络读写。
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try{
// 创建ServerBootstrap对象,是Netty用于启动NIO服务端的辅助启动类,目的是降低服务端的开发复杂度。
ServerBootstrap b = new ServerBootstrap();
// ServerBootstrap的group方法将两个NIO线程组当作入参传递到ServerBootstrap中。、
// channel方法设置创建的Channel为NioServerSocketChannel,功能对应于JDK NIO类库中的ServerSocketChannel类。
// option方法配置NioServerSocketChannel的TCP参数,此处将它的backlog设置为1024。
// childHandler方法绑定I/O事件的处理类ChildChannelHandler,它的作用类似于Reactor模式中的Handler类,
//       主要用于处理网络I/P事件,例如记录日志、对消息进行编解码等。
b.group(bossGroup,workerGroup)
        .channel(NioServerSocketChannel.class)
        .option(ChannelOption.SO_BACKLOG, 1024)
        .childHandler(new ChildChannelHandler());
// 绑定端口,同步等待成功
// 服务端启动辅助类配置完成之后,调用bind方法绑定监听端口。
// 同步阻塞方法sync等待绑定操作完成,并返回一个ChannelFuture。
// ChannelFuture功能类似于JDK的java.util.concurrent.Future,主要用于异步操作的通知回调。
ChannelFuture f = b.bind(port).sync();
// 等待服务端监听端口关闭
// 进行阻塞,等待服务端链路关闭之后main函数才退出。
f.channel().closeFuture().sync();
}finally{
// 优雅退出,释放线程资源
// 调用NIO线程组的shutdownGraceFully进行优雅退出,它会释放跟shutdownGracefully相关联的资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeServerHandler());
}
}
public static void main(String[] args) throws Exception{
int port = 8080;
if(null != args && args.length > 0){
try{
port = Integer.valueOf(args[0]);
}catch(NumberFormatException e){
// 采用默认值
}
}
new TimeServer().bind(port);
}
}

        Class : TimeServerHandler

package com.phei.netty.chap3;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import java.util.Date; //用于对网络事件进行读写操作
public class TimeServerHandler extends ChannelHandlerAdapter { @Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
// ByteBuf类似与java.nio.ByteBuffer对象。
ByteBuf buf = (ByteBuf) msg;
// readableBytes方法可以获取缓冲区可读的字节数
byte[] req = new byte[buf.readableBytes()];
// readBytes方法将缓冲区中的字节数组赋值到新的byte数组中。
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());
// 通过ChannelHandlerContext的write方法异步发送应答消息给客户端
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// 将消息发送队列中的消息写入到SocketChannel中发送给对方
/* 为了防止频繁地唤醒Selector进行消息发送,
Netty的write方法并不直接将消息写入SocketChannel中,
调用write方法只是把待发送的消息放到发送缓冲数组中,
在通过调用flush方法,将发送缓冲区中的消息全部写到SocketChannel中。*/
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
/* 当发生异常时,关闭ChannelHandlerContext
,释放和ChannelHandlerContext相关联的句柄等资源。*/
ctx.close();
} }

    3.3 Netty客户端开发

      Class : TimeClient

package com.phei.netty.chap3;

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; import org.springframework.util.StringUtils; public class TimeClient { public void connect(int port,String host) throws Exception{
// 配置客户端NIO线程组
// 创建客户端处理I/O读写的NioEventLoopGroup线程组
EventLoopGroup group = new NioEventLoopGroup();
try{
// 创建客户端辅助启动类Bootstrap
Bootstrap b = new Bootstrap();
// 配置客户端辅助启动类
b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true).handler(new ChannelInitializer<SocketChannel>(){ /* initChannel方法:当创建NioSocketChannel成功之后,进行初始化时
将它的ChannelHandler设置到ChannelPipeline中,用于处理网络I/O事件*/
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeClientHandler());
} });
// 发起异步连接操作
// 调用connect方法发起异步连接,然后调用同步方法等待连接成功
ChannelFuture f = b.connect(host,port).sync();
// 等待客户端链路关闭
// 当客户端连接关闭之后,客户端主函数退出,退出之前释放NIO线程组的资源。
f.channel().closeFuture().sync();
}finally{
// 优雅退出,释放NIO线程组
group.shutdownGracefully();
}
} public static void main(String[] args) throws Exception{
int port = 8080;
if(null != args && args.length > 0){
try{
port = Integer.valueOf(args[0]);
}catch(NumberFormatException e){
// 采用默认值
}
}
new TimeClient().connect(port, "127.0.0.1");
}
}

      Class : TimeClientHandler

package com.phei.netty.chap3;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; import java.util.logging.Logger; public class TimeClientHandler extends ChannelHandlerAdapter { private static final Logger logger = Logger.getLogger(TimeClientHandler.class.getName());
private final ByteBuf firstMessage;
public TimeClientHandler() {
byte[] req = "QUERY TIME ORDER".getBytes();
firstMessage = Unpooled.buffer(req.length);
firstMessage.writeBytes(req);
}
/* 当客户端和服务端TCP链路建立成功之后,
Netty的NIO线程会调用channelActive方法,
发送查询事件的指令给服务端,
调用ChannelHandlerContext的writeAndFlush方法将请求消息发送给服务端*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(firstMessage);
}
// 当服务端返回应答消息时,channelRead方法被调用。
// 从Netty的ByteBuf中读取并打印应答消息
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req,"UTF-8");
System.out.println("Now is : " + body);
}
// 发生异常时,打印异常日志,释放客户端资源
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
// 释放资源
logger.warning("Unexpected exception from downstream : " + cause.getMessage());
ctx.close();
}
}

    3.4 运行和调试

      3.4.1 服务端和客户端的运行

      3.4.2 打包和部署

    3.5 总结

啦啦啦

啦啦啦

啦啦啦

第三章 Netty入门应用的更多相关文章

  1. (入门篇 NettyNIO开发指南)第三章-Netty入门应用

    作为Netty的第一个应用程序,我们依然以第2章的时间服务器为例进行开发,通过Netty版本的时间服务报的开发,让初学者尽快学到如何搭建Netty开发环境和!运行Netty应用程序. 如果你已经熟悉N ...

  2. 第三章 Docker 入门

    第三章 docker 入门 3.1 确保docker已经就绪 首先查看docker程序是否存在,功能是否正常 [#3#cloudsoar@cloudsoar-virtual-machine ~]$su ...

  3. Netty 系列(三)Netty 入门

    Netty 系列(三)Netty 入门 Netty 是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠性的网络服务器和客户端程序.更多请参考:Netty Github 和 Netty中文 ...

  4. JAVA通信系列三:Netty入门总结

    一.Netty学习资料 书籍<Netty In Action中文版> 对于Netty的十一个疑问http://news.cnblogs.com/n/205413/ 深入浅出Nettyhtt ...

  5. 《Netty权威指南》(三)Netty 入门应用

    Netty 服务端   Netty 客户端

  6. Android深度探索HAL与驱动开发 第三章 Git入门

    Git功能十分复杂,简单来说它使你的开发更为快捷和可控,尤其是在开源项目上展现的友好的交互和回馈. 熟悉一些git指令操作对开发者的帮助可以避免开发者受到一些外在因素打断开发进度,甚至延误项目的che ...

  7. 第三章·Logstash入门-部署与测试

    1.Logstash环境准备与安装 Logstash环境准备 关闭防火墙 #CentOS6 关闭防火墙 [root@elkstack01 ~]# /etc/init.d/iptables stop # ...

  8. 第三章 Git的入门 - 读书笔记

    Android驱动月考3 第三章 Git的入门 - 读书笔记 对于Github,这是全世界最大的开源平台,你可以把你做的项目在这里开源,把你发现的一些新技术在这里开源,向全世界的开发者们分享,大家都彼 ...

  9. Android系统移植与驱动开发--第三章 Git使用入门及在学习中有感

    第三章 Git使用入门 使用Git的目的是减少各种版本的Linux的压缩大小,提供源代码在Linux上进行编译. 在这一个章节中,其实就是关键步骤的操作,虽然Git与我们学习的android没有很大的 ...

随机推荐

  1. 菜鸟互啄:WINFORM如何实现无聚焦框的Button按钮

    当我们将一个button按钮设置如下属性时,总有一个聚焦框来困扰着我们 button1.FlatStyle = FlatStyle.Flat; 我们想要的效果是这样的: 但当使用了Tab切换焦点时 发 ...

  2. USACO 3.4 Electric Fence

    Electric FenceDon Piele In this problem, `lattice points' in the plane are points with integer coord ...

  3. tomcat部署war包时连接被重置(修改tomcat上传限制)

    相对目录:apache-tomcat-7.0.67/webapps/manager/WEB-INF/web.xml 500M的计算:500*1024*1024 <multipart-config ...

  4. jquery插件autoComplete自动弹出

    导入 <link rel="stylesheet" href="${ctx }/static/plugins/jQuery-autoComplete-master/ ...

  5. 打印java堆栈信息

    使用如下命令: kill -3 {pid} 可以打印指定线程的堆栈信息到tomcat的catalina.out日志中.在性能测试过程中,可以观察响应时间的曲线,如果突然出现波峰则抓取当前时间点tomc ...

  6. android 界面布局

    一.LinearLayout LinearLayout 又称作线性布局,是一种非常常用的布局,它所包含的控件在线性方向上依次排列. android:orientation="horizont ...

  7. Scala 控制结构

    Scala内建的控制结构屈指可数,仅有if, while, for, match, try和函数调用而已. 几乎所有的Scala控制结构都会产生某个值(while和 do while虽然不能产生有意义 ...

  8. The APR based Apache Tomcat Native library tomcat启动错误

    The APR based Apache Tomcat Native library which allows optimal performance in production environmen ...

  9. 连接pgsql

    package com.jpzhutech.select; import java.sql.Connection; import java.sql.DriverManager; import java ...

  10. Python学习笔记——基础篇【第五周】——正则表达式(re)

    目录 1.简介 2.字符匹配 1.简介:就其本质而言,正则表达式(或 RE)是一种小型的.高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现.正则表达式模式被编译 ...