3.2 Netty 服务端开发

  • TimeServer.java
public class TimeServer {public void bind(int port) throws Exception {// 配置服务端的NIO线程组EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG,1024).childHandler(new ChildChannelHandler());// 绑定端口,同步等待成功ChannelFuture f = b.bind(port).sync();// 等待服务端监听端口关闭f.channel().closeFuture().sync();} finally {// 优雅退出,释放线程池资源bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}private class ChildChannelHandlerextends ChannelInitializer<SocketChannel>{@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {socketChannel.pipeline().addLast(new TimeServeHandler());}}public static void main(String[] args) throws Exception{int port = 8080;if (args != null && args.length > 0) {try {port = Integer.valueOf(args[0]);} catch (NumberFormatException e) {// 采用默认值}}new TimeServer().bind(port);}
}

我 们 从 bind 方 法 开 始 学 习 , 在 代 码 第 5~6 行 创 建 了 两 个 NioEventLoopGroup 实 例 。NioEventLoopGroup 是 个 线 程 组 , 它 包 含 了 一 组 NIO 线 程 , 专 门 用 于 网 络 事 件 的 处 理 , 实际 上 它 们 就 是 Reactor 线 程 组 。 这 里 创 建 两 个 的 原 因 是 一 个 用 于 服 务 端 接 受 客 户 端 的 连 接 ,另 一 个 用 于 进 行 SocketChanneI 的 网 络 读 写 。 第 8行 创 建 ServerBootstrap 对 象 , 它 是 Netty用 于 启 动 NIO 服 务 端 的 辅 助 启 动 类 , 目 的 是 降 低 服 务 端 的 开 发 复 杂 度 。 第 9行 调 用ServerBootstrap 的 group 方 法 , 将 两 个 NIO 线 程 组 当 作 入 参 传 递 到 ServerBootstrap 中 。 接着 设 置 创 建 的 Channel 为 NioServerSocketChannel, 它 的 功 能 对 应 于 JDK NIO 类 库中的ServerSocketChannel 类 。 然 后 配 置 NioServerSocketCh annel 的 TC P 参 数 , 此 处 将 它 的 backlog
设 置 为 1024 , 最 后 绑 定 I/O 事 件 的 处 理 类 ChildChannelHandler , 它 的 作 用 类 似 于 Reactor模 式 中 的 Handler 类 , 主 要 用 于 处 理 网 络 1 / 0 事 件 , 例 如 记 录 日 志 、 对 消 息 进 行 编 解 码 等 。

服 务 端 启 动 辅 助 类 配 置 完 成 之 后 , 调 用 它 的 bind 方 法 绑 定 监 听 端 口 , 随 后 , 调 用 它的 同 步 阻 塞 方 法 sync 等 待 绑 定 操 作 完 成 。 完 成 之 后 Netty 会 返 回 一 个 ChannelFuture , 它的 功 能 类 似 于 JDK 的 java.util.concurrent.Future , 主 要 用 于 异 步 操 作 的 通 知 回 调 。

第 16行 使 用 f.channel().closeFuture().sync() 方 法 进 行 阻 塞 , 等 待 服 务 端 鲢 路 关 闭 之 后main 函 数 才 退 出 。

第 19~20 行 调 用 NIO 线 程 组 的 shutdownGracefully 进 行 优 雅 退 出 , 它 会 释放跟shutdownGracefuIIy 相 关 联 的 资 源 。

  • TimeServeHandler.java
public class TimeServeHandler extends ChannelHandlerAdapter {@Overridepublic 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("The time server receive order : " + body);String currentTime ="QUERY TIME ORDER".equalsIgnoreCase(body)? new java.util.Date(System.currentTimeMillis()).toString() : "BAD ORDER";ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());ctx.write(resp);}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.flush();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}
}

第 5 行 做 类 型 转 换 , 将 msg 转 换 成 Netty 的 ByteBuf 对 象 。 ByteBuf 类 似 于 JDK 中 的java.nio.ByteBuffer 对 象 , 不 过 它 提 供 了 更 加 强 大 和 灵 活 的 功 能 。 通 过 ByteBuf 的readabl e Bytes 方 法 可 以 获 取 缓 冲 区 可 读 的 字 节 数 , 根 据 可 读 的 字 节 数 创 建 byte 数 组 , 通 过ByteBuf 的 read Bytes 方 法 将 缓 冲 区 中 的 字 节 数 组 复 制 到 新 建 的 byte 数 组 中 , 最 后 通 过 new
string 构 造 函 数 获 取 请 求 消 息 。 这 时 对 请 求 消 息 进 行 判 断 , 如 果 是 "QUERY TIME ORDER"则 创 建 应 答 消 息 , 通 过 ChanneIHandIerContext 的 write 方 法 异 步 发 送 应 答 消 息 给 客 户 端 。

第 20 行 我 们 发 现 还 调 用 了 ChannelHandlerContext的 flush 方 法 , 它 的 作 用 是 将 消 息发 送 队 列 中 的 消 息 写 入 到 SocketChannel 中 发 送 给 对 方 。 从 性 能 角 度 考 虑 , 为 了 防 止 频 繁地 唤 醒 SeIector 进 行 消 息 发 送 , Netty 的 write 方 法 并 不 直 接 将 消 息 写 入 SocketChanneI 中 ,调 用 write 方 法 只 是 把 待 发 送 的 消 息 放 到 发 送 缓 冲 数 组 中 , 再 通 过 调 用 flush 方 法 , 将 发 送缓 冲 区 中 的 消 息 全 部 写 到 SocketChannel 中 。

第 25 行 , 当 发 生 异 常 时 , 关 闭 ChanneIHandIerContext , 释 放 和 ChanneIHandIerContext相 关 联 的 句 柄 等 资 源 。通 过 对 代 码 进 行 统 计 分 析 可 以 看 出 , 不 到 30 行 的 业 务 逻 辑 代 码 , 即 完 成 了 NIO 服 务端 的 丌 发 , 相 比 于 传 统 基 于 JDK NIO 原 生 类 库 的 服 务 端 , 代 码 量 大 大 减 少 , 开发难 度 也降 低 了 很 多 。

3.3 Netty 客户端开发

  • TimeClient.java
public class TimeClient {public void connect(int port, String host)  throws Exception {// 配置客户端NIO 线程组EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {socketChannel.pipeline().addLast(new TimeClientHandler());}});// 发起异步连接操作ChannelFuture f = b.connect(host, port).sync();// 当代客户端链路关闭f.channel().closeFuture().sync();} finally {// 优雅退出,释放NIO线程组group.shutdownGracefully();}}/*** @param args* @throws Exception*/public static void main(String[] args) throws Exception {int port = 8080;if (args != null && args.length > 0) {try {port = Integer.valueOf(args[0]);} catch (NumberFormatException e) {// 采用默认值}}new TimeClient().connect(port, "127.0.0.1");}
}

我 们 从 connect 方 法 讲 起 , 在 第 5行 首 先 创 建 客 户 端 处 理 I/O 读 写 的 NioEventLoopGroup 线 程 组 , 然 后 继 续 创 建 客 户 端 辅 助 启 动 类 Bootstrap , 随 后 需 要 对 其 进 行 配 置 。 与 服务 端 不 同 的 是 , 它 的 ChanneI 需 要 设 置 为 N ioSocketChanneI , 然 后 为 其 添 加 HandIer. 此 处为 了 简 单 直 接 创 建 匿 名 内 部 类 , 实 现 initChannel 方 法 , 其 作 用 是 当 创 建 NioSocketChanneI
成 功 之 后 , 在 进 行 初 始 化 时 , 将 它 的 ChannelHandler 设 置 到 ChannelPipeline 中 , 用 于 处 理网 络 I/O 事 件 。

客 户 端 启 动 辅 助 类 设 置 完 成 之 后 , 调 用 connect 方 法 发 起 异 步 连 接 , 然 后 调 用 同 步 方法 等 待 连 接 成 功 。

最 后 , 当 客 户 端 连 接 关 闭 之 后 , 客 户 端 主 函 数 退 出 , 退 出 之 前 释 放 NIO 线 程 组 的 资 源 。

  • TimeClientHandler.java
public class TimeClientHandler extends ChannelHandlerAdapter {private static final Logger logger =Logger.getLogger(TimeClientHandler.class.getName());private final ByteBuf firstMessage;// Creates a client-side handler.public TimeClientHandler() {byte[] req = "QUERY TIME ORDER".getBytes();firstMessage = Unpooled.buffer(req.length);firstMessage.writeBytes(req);}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {ctx.writeAndFlush(firstMessage);}@Overridepublic 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");}
}

这 里 重 点 关 注 三 个 方 法 : channelActive 、 channelRead 和 exceptionCaught0 当 客 户 端和 服 务 端 TCP 链 路 建 立 成 功 之 后 , Netty 的 NIO 线 程 会 调 用 channelActive 方 法 , 发 送 查询 时 间 的 指 令 给 服 务 端 , 调 用 ChannelHandlerContext 的 writeAndFlush 方 法 将 请 求 消 息 发送 给 服 务 端 。
当 服 务 端 返 回 应 答 消 息 时 , channelRead 方 法 被 调 用 , 第 39 ~ 43 行 从 Netty 的 ByteBuf中 读 取 并 打 印 应 答 消 息 。
第 21~26 行 , 当 发 生 异 常 时 , 打 印 异 常 日 志 , 释 放 客 户 端 资 源 。

netty权威指南-第三章——netty入门应用相关推荐

  1. netty权威指南第三版_Hadoop权威指南(第二版及第三版)

    书籍简介 全书5部分24章,第Ⅰ部分介绍Hadoop基础知识,主题涉及Hadoop.MapReduce.Hadoop分布式文件系统.YARN.Hadoop的I/O操作. 第Ⅱ部分介绍MapReduce ...

  2. netty权威指南学习笔记一——NIO入门(4)AIO

    NIO2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现.异步通道提供以下两种方式获取操作结果. 1.通过java.util.concurrent.Future 类来表示异步操 ...

  3. Asterisk权威指南/第三章 安装Asterisk

    在这一章我们将详细介绍如何从源代码安装Asterisk.很多人回避这种方法,说它太难了,又耗时间.我们在这里想证明的是从源代码安装Asterisk其实没那么难.更重要的是,我们想为你提供一个最好的As ...

  4. CUDA C编程权威指南 第三章 CUDA执行模型

    基础 每个GPU有多个SM(streaming multiprocessor) 当启动一个grid时,它的block会被分配给多个SM上执行,一个block一旦被调度到一个SM上,则这个block只会 ...

  5. Netty权威指南(四)TCP粘包/拆包问题

    TCP粘包/拆包问题解决之道 上一章 一.介绍 1.1 TCP粘包/拆包问题说明 1.2 TCP粘包/拆包发生的原因 1.3 粘包问题的解决策略 二.未考虑TCP粘包导致的功能异常案例 2.1 Tim ...

  6. IT人物之《Netty权威指南》中文作者 专访华为李林锋:我与Netty那些不得不说的事

    摘要:Netty是业界最流行的NIO框架之一,它的健壮性.功能.性能.可定制性和可扩展性在同类框架中都是首屈一指的.近日,CSDN采访了Netty领域的权威人士李林锋,请他分享Netty开发的经验之道 ...

  7. 《Netty权威指南》笔记 —— 第二十、二十一、二十二, 二十三章

    <Netty权威指南>笔记--Netty高级特性 第20章 Netty架构剖析 Reactor通信调度层 职责链 ChannelPipeline 业务逻辑编排层 关键架构质量属性 高性能 ...

  8. netty权威指南第一章

    本章内容如下: 5种网络I/O模型的介绍 I/O多路复用的介绍 1.I/O基础入门 在Java1.4之前,Java对I/O的支持不完善,开发人员在开发高性能I/O的程序时,会面临以下问题: 没有数据缓 ...

  9. 《Netty权威指南 第2版》学习笔记(1)---服务端与客户端开发入门

    前言 Netty权威指南中以时间服务器为入门案例,演示了如何通过Netty完成了服务端与客户端之间的交互过程. 在开始使用Netty开发之前,先回顾一下使用NIO进行服务端开发的步骤. 创建Serve ...

  10. [201504][Netty 权威指南][第2版][李林锋][著]

    [201504][Netty 权威指南][第2版][李林锋][著] https://github.com/wuyinxian124/nettybook2 基础篇 走进 Java NIO 第 1 章 J ...

最新文章

  1. 只能输入字母的c语言程序设计教程课后答案,c语言程序设计基础教程_习题答案20120319...
  2. http,session,cookie
  3. 51nod-有限背包计数问题【dp】
  4. 消消乐实现下坠_JavaScript有多强大,实现消消乐小游戏
  5. VS Code 主题配置
  6. 中小微企业房抵贷业务场景介绍
  7. Google 程序员消灭 Bug 的 5 大法宝!
  8. 腾讯校园招聘笔试 2019-8-17 第四题
  9. 分享一个非常不错的SSH工具
  10. 解压版tomcat7配置
  11. 一打卡作弊软件CEO被判5年6个月,网友:这也太...
  12. Eclipse美化操作
  13. 群赛 round#5 解题报告(superoxide,choice,rpwt)
  14. 个股和股票池的beta系数的估算
  15. linux 蓝牙hci,实战Linux Bluetooth编程(三) HCI层编程
  16. 我们如何走到今天:重塑世界的6项创新
  17. NLPCC'22 | 一种兼具准确性和多样性的图像风格化描述生成框架
  18. 若有恒,何必三更眠五更起;最无益,莫过一日曝十日寒。
  19. Games101-课程20笔记
  20. 金弘同创:拼多多怎么退保证金

热门文章

  1. 华为p10刷原生android,华为p10怎么刷机 华为p10刷机方法【详细介绍】
  2. 【无人驾驶入门】一、概述
  3. linux释放分区命令,Linux fdisk命令操作磁盘(添加、删除、转换分区等)
  4. Air应用:Splus微博,wing微博
  5. Head First Java 目录结构
  6. j2000 经度_j2000坐标系转换WGS84坐标,看不太懂
  7. dell笔记本驱动安装失败_如何以正确的顺序重新安装驱动程序 | Dell 中国
  8. 【收益管理】单资源容量控制(2)先从报童模型谈起!
  9. 使用BarTender连接Excel文件批量打印图片
  10. 电视信号服务器,基于Web服务器远程控制数字电视信号节目源再利用系统