Netty入门(二)时间服务器及客户端
在这个例子中,我在服务器和客户端连接被创立时发送一个消息,然后在客户端解析收到的消息并输出。并且,在这个项目中我使用 POJO 代替 ByteBuf 来作为传输对象。
一、服务器实现
1. 首先我们自定义传输数据对象
1 package com.coder.client;2 3 import java.util.Date;4 5 /**6 * 自定义时间数据类7 * @author Coder8 *9 */ 10 public class Time { 11 private final long value; 12 13 public Time() { 14 // 除以1000是为了使时间精确到秒 15 this(System.currentTimeMillis() / 1000L); 16 } 17 18 public Time(long value) { 19 this.value = value; 20 } 21 22 public long value() { 23 return value; 24 } 25 26 @Override 27 public String toString() { 28 return new Date((value()) * 1000L).toString(); 29 } 30 }
2. 然后我们需要自定义服务器数据编码类
1 package com.coder.server;2 3 import com.coder.client.Time;4 5 import io.netty.buffer.ByteBuf;6 import io.netty.channel.ChannelHandlerContext;7 import io.netty.handler.codec.MessageToByteEncoder;8 9 /** 10 * 服务器数据编码类 11 * @author Coder 12 * 13 */ 14 public class TimeEncoderPOJO extends MessageToByteEncoder<Time> { 15 16 // 发送数据时调用 17 @Override 18 protected void encode(ChannelHandlerContext ctx, Time msg, ByteBuf out) throws Exception { 19 // 只传输当前时间,精确到秒 20 out.writeInt((int)msg.value()); 21 } 22 23 }
3. 也需要自定义服务器的业务逻辑类,如下:
1 package com.coder.server;2 3 import com.coder.client.Time;4 5 import io.netty.channel.ChannelFuture;6 import io.netty.channel.ChannelFutureListener;7 import io.netty.channel.ChannelHandlerContext;8 import io.netty.channel.ChannelInboundHandlerAdapter;9 10 /** 11 * 服务器解码器 12 * 连接建立时发送当前时间 13 * @author Coder 14 * 15 */ 16 public class TimeServerHandlerPOJO extends ChannelInboundHandlerAdapter { 17 /** 18 * 连接建立的时候并且准备进行通信时被调用 19 */ 20 @Override 21 public void channelActive(final ChannelHandlerContext ctx) throws Exception { 22 // 发送当前时间信息 23 ChannelFuture f = ctx.writeAndFlush(new Time()); 24 // 发送完毕之后关闭 Channel 25 f.addListener(ChannelFutureListener.CLOSE); 26 } 27 28 @Override 29 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 30 cause.printStackTrace(); 31 ctx.close(); 32 } 33 }
4. 有了上面的代码,我们就可以实现服务器程序了,如下:
1 package com.coder.server;2 3 import io.netty.bootstrap.ServerBootstrap;4 import io.netty.channel.ChannelFuture;5 import io.netty.channel.ChannelInitializer;6 import io.netty.channel.ChannelOption;7 import io.netty.channel.EventLoopGroup;8 import io.netty.channel.nio.NioEventLoopGroup;9 import io.netty.channel.socket.SocketChannel; 10 import io.netty.channel.socket.nio.NioServerSocketChannel; 11 12 public class TimeServerPOJO { 13 private int port; 14 15 public TimeServerPOJO(int port) { 16 this.port = port; 17 } 18 19 public void run() throws Exception { 20 EventLoopGroup bossGroup = new NioEventLoopGroup(); // 用来接收进来的连接 21 EventLoopGroup workerGroup = new NioEventLoopGroup(); // 用来处理已经被接收的连接 22 System.out.println("准备运行端口:" + port); 23 24 try { 25 ServerBootstrap b = new ServerBootstrap(); // 启动NIO服务的辅助启动类 26 b.group(bossGroup, workerGroup) 27 .channel(NioServerSocketChannel.class) // 这里告诉Channel如何接收新的连接 28 .childHandler( new ChannelInitializer<SocketChannel>() { 29 @Override 30 protected void initChannel(SocketChannel ch) throws Exception { 31 // 自定义处理类 32 // 注意添加顺序 33 ch.pipeline().addLast(new TimeEncoderPOJO(),new TimeServerHandlerPOJO()); 34 } 35 }) 36 .option(ChannelOption.SO_BACKLOG, 128) 37 .childOption(ChannelOption.SO_KEEPALIVE, true); 38 39 // 绑定端口,开始接收进来的连接 40 ChannelFuture f = b.bind(port).sync(); 41 42 // 等待服务器socket关闭 43 f.channel().closeFuture().sync(); 44 } catch (Exception e) { 45 workerGroup.shutdownGracefully(); 46 bossGroup.shutdownGracefully(); 47 } 48 } 49 50 public static void main(String[] args) throws Exception { 51 int port = 8080; 52 new TimeServer(port).run(); 53 } 54 }
执行代码后如下:
这时候服务器在等待客户端的连接(非阻塞)。
二、客户端实现
客户端的实现与服务器类似。
1. 自定义客户端数据解码类
1 package com.coder.client;2 3 import java.util.List;4 5 import io.netty.buffer.ByteBuf;6 import io.netty.channel.ChannelHandlerContext;7 import io.netty.handler.codec.ByteToMessageDecoder;8 9 public class TimeDecoderPOJO extends ByteToMessageDecoder { 10 /** 11 * 有新数据接收时调用 12 * 为防止分包现象,先将数据存入内部缓存,到达满足条件之后再进行解码 13 */ 14 @Override 15 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { 16 if(in.readableBytes() < 4) { 17 return; 18 } 19 20 // out添加对象则表示解码成功 21 out.add(new Time(in.readUnsignedInt())); 22 } 23 }
2. 自定义客户端业务逻辑类
1 package com.coder.client;2 3 import io.netty.channel.ChannelHandlerContext;4 import io.netty.channel.ChannelInboundHandlerAdapter;5 6 /**7 * 客户端数据处理类8 * @author Coder9 * 10 */ 11 public class TimeClientHandlerPOJO extends ChannelInboundHandlerAdapter { 12 @Override 13 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 14 // 直接将信息转换成Time类型输出即可 15 Time time = (Time)msg; 16 System.out.println(time); 17 ctx.close(); 18 } 19 20 @Override 21 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 22 cause.printStackTrace(); 23 ctx.close(); 24 } 25 }
3. 客户端程序实现
Netty 客户端的通信步骤大致为:
- 创建一个 NIO 线程组,用于处理服务器与客户端的连接,客户端不需要用到 boss worker。
- 创建一个 Bootstrap 对象,配置 Netty 的一系列参数,由于客户端 SocketChannel 没有父亲,所以不需要使用 childoption。
- 创建一个用于实际处理数据的类ChannelInitializer,进行初始化的准备工作,比如设置接受传出数据的字符集、格式以及实际处理数据的接口。
- 配置服务器 IP 和端口号,建立与服务器的连接。
1 package com.coder.client;2 3 import io.netty.bootstrap.Bootstrap;4 import io.netty.channel.ChannelFuture;5 import io.netty.channel.ChannelInitializer;6 import io.netty.channel.ChannelOption;7 import io.netty.channel.EventLoopGroup;8 import io.netty.channel.nio.NioEventLoopGroup;9 import io.netty.channel.socket.SocketChannel; 10 import io.netty.channel.socket.nio.NioSocketChannel; 11 12 public class TimeClientPOJO { 13 public static void main(String[] args) throws Exception{ 14 String host = "127.0.0.1"; // ip 15 int port = 8080; // 端口 16 EventLoopGroup workerGroup = new NioEventLoopGroup(); 17 18 try { 19 Bootstrap b = new Bootstrap(); // 与ServerBootstrap类似 20 b.group(workerGroup); // 客户端不需要boss worker 21 b.channel(NioSocketChannel.class); 22 b.option(ChannelOption.SO_KEEPALIVE, true); // 客户端的socketChannel没有父亲 23 b.handler(new ChannelInitializer<SocketChannel>() { 24 @Override 25 protected void initChannel(SocketChannel ch) throws Exception { 26 // POJO 27 ch.pipeline().addLast(new TimeDecoderPOJO() ,new TimeClientHandlerPOJO()); 28 } 29 }); 30 31 // 启动客户端,客户端用connect连接 32 ChannelFuture f = b.connect(host, port).sync(); 33 34 // 等待连接关闭 35 f.channel().closeFuture().sync(); 36 } finally { 37 workerGroup.shutdownGracefully(); 38 } 39 } 40 }
三、测试
先运行服务器程序,运行结果如下图:
然后运行客户端程序,运行结果如下图:
需要注意的是,Eclipse 是可以同时运行多个 Java 程序的,可以通过点击
来切换不同程序的控制台输出窗口。
Netty入门(二)时间服务器及客户端相关推荐
- 建立一个时间服务器要求客户端每天早上九点自动同步服务端时间
建立一个时间服务器要求每天早上九点服务器自动同步时间 环境要求 一.搭建时间服务器 1.服务端: 2.客户端 二.设置循环例行性任务 环境要求 1.有一个服务端和一个客户端. 2.需要有yum源,下载 ...
- SOCKET编程-时间服务器和客户端的实现
文章目录 UNIX_NET 获取服务器时间 connect函数 获取时间客户端程序实现 获取时间服务器实现 小技巧 宏定义的使用&&变参函数的宏定义实现 源码地址 UNIX_NET 获 ...
- Linux socket编程(二) 服务器与客户端的通信
http://www.cnblogs.com/-Lei/archive/2012/09/04/2670964.html 上一篇写了对套接字操作的封装,这一节使用已封装好的Socket类实现服务器与客户 ...
- Centos7时钟服务器和客户端搭建(NTP)
一.角色设计(二者能通讯) 1.服务器 : 192.168.137.3 2.客户端: 192.168.137.6 二.服务器和客户端ntp和ntpdate服务安装检查 1. 在服务器和客户端同时检 ...
- ntp网络时间服务器的详细介绍
ntp网络时间服务器的详细介绍 ntp网络时间服务器的详细介绍 NTP属于运用层协议(依据UDP传输,运用的端口号为123),用来同步网络中分布式时间服务器和客户端之间的时间,使网络中的设备供应依据一 ...
- HQYJ学习随笔--服务器与客户端(linux)
文章目录 系列文章目录 前言 一.什么是服务器,什么又是客户端? 二.UDP服务器与客户端. 1..服务器 2..客户端 总结 前言 服务器端(Server) 是为客户端(Client)服务的,服务的 ...
- Windows环境下时间服务器(NTP)的创建与应用
一.Windows时间服务器建立 1)登录用来作为时间服务器的主机"192.168.1.100",运行命令gpedit.msc打开"本地组策略编辑器"窗口,打开 ...
- ntp server 配置参数_NTP时间服务器的配置
NTP 用于在分布式时间服务器与客户端之间进行时间同步,它定义了时间同步实现过程中所使用的结构.算法.实体和协议.NTP 协议基于TCP /IP 中的IP 和UDP 协议栈,也可被其他协议组使用. 从 ...
- 时钟服务器工作原理,NTP时间服务器工作原理
文章目录 [隐藏] NTP简介 NTP工作原理 NTP工作模式 NTP简介 NTP(Network Time Protocol, 网络时间协议)是由RFC 1305定义的时间同步协议,用来在分布式时间 ...
最新文章
- windows下mysql开启慢查询
- python做电脑软件-程序员带你十天快速入门Python,玩转电脑软件开发(一)
- 浅谈腾讯微博与新浪微博的优劣
- 应用场景的多样,奠定了区块链的未来
- OpenGL shadow mapping 阴影贴图的实例
- Spring事务管理TransactionManager
- Java开发笔记(五十六)利用枚举类型实现高级常量
- SpringCloud学习笔记022---SpringBoot中集成使用MongoDb进行增删改查
- 导航栏使用引导、下载资源支持试读、CSDN年终重磅福利来袭……
- 设计模式—工厂模式(思维导图)
- 定时器和promise_如何讲清楚Promise?
- ECLIPSE软件安装MyBatis插件 MyBatis Generator
- 第二届亚太应用经济学会博硕士论文研讨会长沙落幕
- 神经网络可视化工具Netron
- python使用gmail发送邮件
- Wangle源码分析:ServerBootstrap
- SSR门户项目爬坑之路(一)
- 《绮梦朦胧,一眼浮生醉流年》
- IT项目经理必备的五种能力
- 徒步健步打卡活动,徒步过程拍照打卡,让徒步更有趣。box-sizing 属性允许我们在框的总宽度
热门文章
- ARIMA模型的介绍
- MXNet的Model API
- mysql 索引合并_MySQL 索引合并(Index Merge)优化
- 计算机应用技木就业前京,计算机专业毕业的研究生在京就业情况及启示.doc
- 安卓 usb音量调节_戴尔推出面向Teams和Zoom视频通话的USB-C免提适配器
- webgl编程指南源码_ThreeJS 源码剖析之 Renderer(一)
- springcloud feign 服务调用其他服务_微服务实战——SpringCloud与Feign集成
- 筒灯智能驱动芯片作用_如然之光,魅族 Lipro 智能家居发布首期健康照明系列--智能设备 -...
- 连接真机开发安卓(Android)移动app MUI框架 反馈意见、忘记密码、登录、底部选项卡、联系我们、导航等页面代码可拿——混合式开发(六)
- Spring中@Async