本文承接上文《【Netty】入门Netty官方例子解析(一)写个 Discard Server》
,接下来讲解官网文档中Netty入门官方例子第二个例子 Time Server
原文这个章节,是为了构建一个模拟时间服务器的代码,可以供其他客户端查询时间,可以通过rdate(后文有解释)命令来验证。

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;/*** Discards any incoming data.*/
public class DiscardServer {private int port;public DiscardServer(int port) {this.port = port;}public void run() throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap(); // (2)b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // (3).childHandler(new ChannelInitializer<SocketChannel>() { // (4)@Overridepublic void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new DiscardServerHandler());}}).option(ChannelOption.SO_BACKLOG, 128)          // (5).childOption(ChannelOption.SO_KEEPALIVE, true); // (6)// Bind and start to accept incoming connections.ChannelFuture f = b.bind(port).sync(); // (7)// Wait until the server socket is closed.// In this example, this does not happen, but you can do that to gracefully// shut down your server.f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {int port = 8080;if (args.length > 0) {port = Integer.parseInt(args[0]);}new DiscardServer(port).run();}
}
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;public class TimeServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelActive(final ChannelHandlerContext ctx) { // (1)final ByteBuf time = ctx.alloc().buffer(4); // (2)time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));final ChannelFuture f = ctx.writeAndFlush(time); // (3)f.addListener(new ChannelFutureListener() {public void operationComplete(ChannelFuture future) {assert f == future;ctx.close();}}); // (4)}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}
}

当建立连接并准备通信时,将调用channelActive()方法。让我们写一个表示该方法当前时间的32位整数。

要发送新消息,我们需要分配一个包含消息的新缓冲区。我们将要写一个32位整数,因此我们需要一个容量至少为4个字节的ByteBuf。通过ChannelHandlerContext.alloc()获取当前的ByteBufAllocator并分配一个新的缓冲区。

和往常一样,我们编写构造的消息。

但是,等等,flip在哪里?在NIO中发送消息之前,我们不是曾经调用过java.nio.ByteBuffer.flip()吗? ByteBuf没有这种方法,因为它有两个指针。一个用于读取操作,另一个用于写入操作。当您将某些内容写入ByteBuf时,写入器索引会增加,而读取器索引不会改变。读索引和写索引分别表示消息的开始和结束位置。可以参考【Netty】ByteBuf–Netty的数据容器

相反,NIO缓冲区没有提供一种明确的方法来确定消息内容的开始和结束位置,而无需调用flip方法。当您忘记flip缓冲区时会遇到麻烦,因为将不会发送任何内容或发送不正确的数据。在Netty中不会发生这样的错误,因为我们对不同的操作类型有不同的指针。您会发现它使您适应它的生活变得轻松多了-无需flip的生活!

需要注意的另一点是ChannelHandlerContext.write()(和writeAndFlush())方法返回ChannelFuture。 ChannelFuture表示尚未发生的I / O操作。这意味着,由于Netty中的所有操作都是异步的,因此可能尚未执行任何请求的操作。例如,以下代码甚至在发送消息之前就可能关闭连接

Channel ch = ...;
ch.writeAndFlush(message);
ch.close();

因此,您需要在ChannelFuture完成之后调用close()方法,该方法由write()方法返回,并在完成写操作后通知其侦听器。 请注意,close()也可能不会立即关闭连接,它会返回ChannelFuture。

原文中的例子可以用linuxrdate命令访问,记住不是cmd命令行,否则显示乱码。rdate是一个查询日期并支持同步至本地日期的工具,下面的语法取决于版本,我安装的版本并不支持port参数,也因此没有验证成功。不过没关系,下文中有java实现的客户端

客户端
我们java实现一个客户端,来模拟rdate命令一样的效果。

$ rdate -o <port> -p <host>
1
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;public class TimeClient {public static void main(String[] args) throws Exception {EventLoopGroup workerGroup = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap(); // (1)b.group(workerGroup); // (2)b.channel(NioSocketChannel.class); // (3)b.option(ChannelOption.SO_KEEPALIVE, true); // (4)b.handler(new ChannelInitializer<SocketChannel>() {public void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new TimeClientHandler());}});// Start the client.ChannelFuture f = b.connect("localhost", 8088).sync(); // (5)// Wait until the connection is closed.f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();}}
}

1.Bootstrap与ServerBootstrap相似,除了它用于非服务器通道,例如客户端或无连接通道。
2.如果仅指定一个EventLoopGroup,则它将同时用作boss 组和worker 组。 尽管,boss worker并不用于客户端。
3.代替NioServerSocketChannel,NioSocketChannel被用来创建客户端通道
4.请注意,由于客户端SocketChannel没有父级,因此此处不像使用ServerBootstrap那样使用childOption()
5.我们应该调用connect()方法而不是bind()方法。

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;import java.util.Date;public class TimeClientHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {ByteBuf m = (ByteBuf) msg; // (1)try {long currentTimeMillis = (m.readUnsignedInt() - 2208988800L) * 1000L;System.out.println(new Date(currentTimeMillis));ctx.close();} finally {m.release();}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}
}

我们运行下看看效果:
记得先运行DiscardServer ,再运行TimeClient

Thu Jan 16 10:37:34 CST 2020

【Netty】入门Netty官方例子解析(二)Time Server相关推荐

  1. 【Netty】入门Netty官方例子解析(一)写个 Discard Server

    本文以Netty官方给出的列子来讲解Netty带你一步步进入Netty.Netty最全教程在这里 Getting Started 版本 netty4 maven依赖: <!-- https:// ...

  2. 【Netty】入门Netty官方例子解析(三)处理一个基于流的传输 TCP粘包和拆包问题分析和解决

    关于 Socket Buffer的一个小警告 基于流的传输比如 TCP/IP, 接收到数据是存在 socket 接收的 buffer 中.不幸的是,基于流的传输并不是一个数据包队列,而是一个字节队列. ...

  3. 【Netty】Netty 入门案例分析 ( Netty 模型解析 | Netty 服务器端代码 | Netty 客户端代码 )

    文章目录 一. Netty 模型代码解析 二. Netty 案例服务器端代码 1 . 服务器主程序 2 . 服务器自定义 Handler 处理者 三. Netty 案例客户端代码 1 . 客户端主程序 ...

  4. 超详细Netty入门

    思维导图 前言 本文主要讲述Netty框架的一些特性以及重要组件,希望看完之后能对Netty框架有一个比较直观的感受,希望能帮助读者快速入门Netty,减少一些弯路. 一.Netty概述 官方的介绍: ...

  5. 超详细Netty入门,看这篇就够了!

    思维导图 前言 本文主要讲述Netty框架的一些特性以及重要组件,希望看完之后能对Netty框架有一个比较直观的感受,希望能帮助读者快速入门Netty,减少一些弯路. 一.Netty概述 官方的介绍: ...

  6. 《netty入门与实战》笔记-02:服务端启动流程

    为什么80%的码农都做不了架构师?>>>    1.服务端启动流程 这一小节,我们来学习一下如何使用 Netty 来启动一个服务端应用程序,以下是服务端启动的一个非常精简的 Demo ...

  7. OkHttp框架从入门到放弃,解析图片使用Picasso裁剪,二次封装OkHttpUtils,Post提交表单数据...

    OkHttp框架从入门到放弃,解析图片使用Picasso裁剪,二次封装OkHttpUtils,Post提交表单数据 我们这片博文就来聊聊这个反响很不错的OkHttp了,标题是我恶搞的,本篇将着重详细的 ...

  8. Netty入门与实战:仿写微信IM即时通讯系统

    转载自:Netty入门与实战:仿写微信IM即时通讯系统 Netty是互联网中间件领域使用最广泛最核心的网络通信框架,几乎所有互联网中间件或者大数据领域均离不开Netty,掌握Netty是作为初中级工程 ...

  9. Netty入门与实战教程

    前言:都说Netty是Java程序员必须要掌握的一项技能,带着不止要知其然还要知其所以然的目的,在慕课上找了一个学习Netty源码的教程,看了几章后着实有点懵逼.虽然用过Netty,并且在自己的个人网 ...

最新文章

  1. Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version 错误解决
  2. SpringBoot中使用POI实现自定义Excel布局式导出
  3. MySQL配置mycat读写分离:wrapper | Startup failed: Timed out waiting for signal from JVM.
  4. vboxdrv.sh failed modprobe vboxdrv failed. Please use 'dmesg' to find out why
  5. GoldenGate应用拓扑结构(三)
  6. VHD容量调整的方法(保存原有vhd)
  7. lumen安装后输出hello world
  8. 2021-09-09316. 去除重复字母 栈
  9. c++ pdflib 生成中文内容
  10. matlab表示开方,在MATLAB内置功能中,‘sqrt(a)’表示() 答案:对a开方
  11. 蒋正寒计算机编程大赛,重庆大学第七届研究生编程大赛完美收官
  12. 【问题笔记】Android Studio运行或打包时报错:Some file crunching failed, see logs for details
  13. Photoshop Elements 10 All-in-One For Dummies 免积分下载
  14. 大于23的男生女生都该看.看完你会变一个人【转】
  15. 欢迎 V 的到来:简书新浪微博联合认证公告
  16. ES中如何实现随机抽样查询
  17. 30天自制操作系统第9天harib06a
  18. C语言如何输入带空格的字符串?
  19. Oracle-OGG trail 文件大小引起的进程异常 OGG-01172
  20. 基于scrapy下的租房信息爬取与数据展示工具的设计与实现

热门文章

  1. 四分之一常用的非抗菌药物,居然也会抑制人体肠道菌群?
  2. R语言使用aov函数进行单因素协方差分析(One-way ANCOVA)、使用multcomp包的glht函数检验组均值之间所有成对对比差异、通过contrast参数自定义对比组进行组间两两方差分析
  3. pandas基于时序数据计算模型预测推理需要的统计数据(累计时间、长度变化、变化率、方差、均值、最大、最小等):数据持续的时间(分钟)、获得某一节点之后的数据总变化量、获得范围内的统计量
  4. unexpected symbol、unexpected end of input
  5. python使用imbalanced-learn的RandomUnderSampler方法进行下采样处理数据不平衡问题
  6. AttributeError: ‘Series‘ object has no attribute ‘as_matrix‘
  7. python读写压缩文件使用gzip和bz2
  8. 高斯过程及其家族往事
  9. linux bash字符串截取
  10. mysql简拼_mysql实现汉字换拼音,及汉字转简拼