在这个例子中,我在服务器和客户端连接被创立时发送一个消息,然后在客户端解析收到的消息并输出。并且,在这个项目中我使用 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 客户端的通信步骤大致为:

  1. 创建一个 NIO 线程组,用于处理服务器与客户端的连接,客户端不需要用到 boss worker。
  2. 创建一个 Bootstrap 对象,配置 Netty 的一系列参数,由于客户端 SocketChannel 没有父亲,所以不需要使用 childoption。
  3. 创建一个用于实际处理数据的类ChannelInitializer,进行初始化的准备工作,比如设置接受传出数据的字符集、格式以及实际处理数据的接口。
  4. 配置服务器 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. 建立一个时间服务器要求客户端每天早上九点自动同步服务端时间

    建立一个时间服务器要求每天早上九点服务器自动同步时间 环境要求 一.搭建时间服务器 1.服务端: 2.客户端 二.设置循环例行性任务 环境要求 1.有一个服务端和一个客户端. 2.需要有yum源,下载 ...

  2. SOCKET编程-时间服务器和客户端的实现

    文章目录 UNIX_NET 获取服务器时间 connect函数 获取时间客户端程序实现 获取时间服务器实现 小技巧 宏定义的使用&&变参函数的宏定义实现 源码地址 UNIX_NET 获 ...

  3. Linux socket编程(二) 服务器与客户端的通信

    http://www.cnblogs.com/-Lei/archive/2012/09/04/2670964.html 上一篇写了对套接字操作的封装,这一节使用已封装好的Socket类实现服务器与客户 ...

  4. Centos7时钟服务器和客户端搭建(NTP)

    一.角色设计(二者能通讯) 1.服务器 : 192.168.137.3 2.客户端:  192.168.137.6  二.服务器和客户端ntp和ntpdate服务安装检查 1. 在服务器和客户端同时检 ...

  5. ntp网络时间服务器的详细介绍

    ntp网络时间服务器的详细介绍 ntp网络时间服务器的详细介绍 NTP属于运用层协议(依据UDP传输,运用的端口号为123),用来同步网络中分布式时间服务器和客户端之间的时间,使网络中的设备供应依据一 ...

  6. HQYJ学习随笔--服务器与客户端(linux)

    文章目录 系列文章目录 前言 一.什么是服务器,什么又是客户端? 二.UDP服务器与客户端. 1..服务器 2..客户端 总结 前言 服务器端(Server) 是为客户端(Client)服务的,服务的 ...

  7. Windows环境下时间服务器(NTP)的创建与应用

    一.Windows时间服务器建立 1)登录用来作为时间服务器的主机"192.168.1.100",运行命令gpedit.msc打开"本地组策略编辑器"窗口,打开 ...

  8. ntp server 配置参数_NTP时间服务器的配置

    NTP 用于在分布式时间服务器与客户端之间进行时间同步,它定义了时间同步实现过程中所使用的结构.算法.实体和协议.NTP 协议基于TCP /IP 中的IP 和UDP 协议栈,也可被其他协议组使用. 从 ...

  9. 时钟服务器工作原理,NTP时间服务器工作原理

    文章目录 [隐藏] NTP简介 NTP工作原理 NTP工作模式 NTP简介 NTP(Network Time Protocol, 网络时间协议)是由RFC 1305定义的时间同步协议,用来在分布式时间 ...

最新文章

  1. windows下mysql开启慢查询
  2. python做电脑软件-程序员带你十天快速入门Python,玩转电脑软件开发(一)
  3. 浅谈腾讯微博与新浪微博的优劣
  4. 应用场景的多样,奠定了区块链的未来
  5. OpenGL shadow mapping 阴影贴图的实例
  6. Spring事务管理TransactionManager
  7. Java开发笔记(五十六)利用枚举类型实现高级常量
  8. SpringCloud学习笔记022---SpringBoot中集成使用MongoDb进行增删改查
  9. 导航栏使用引导、下载资源支持试读、CSDN年终重磅福利来袭……
  10. 设计模式—工厂模式(思维导图)
  11. 定时器和promise_如何讲清楚Promise?
  12. ECLIPSE软件安装MyBatis插件 MyBatis Generator
  13. 第二届亚太应用经济学会博硕士论文研讨会长沙落幕
  14. 神经网络可视化工具Netron
  15. python使用gmail发送邮件
  16. Wangle源码分析:ServerBootstrap
  17. SSR门户项目爬坑之路(一)
  18. 《绮梦朦胧,一眼浮生醉流年》
  19. IT项目经理必备的五种能力
  20. 徒步健步打卡活动,徒步过程拍照打卡,让徒步更有趣。box-sizing 属性允许我们在框的总宽度

热门文章

  1. ARIMA模型的介绍
  2. MXNet的Model API
  3. mysql 索引合并_MySQL 索引合并(Index Merge)优化
  4. 计算机应用技木就业前京,计算机专业毕业的研究生在京就业情况及启示.doc
  5. 安卓 usb音量调节_戴尔推出面向Teams和Zoom视频通话的USB-C免提适配器
  6. webgl编程指南源码_ThreeJS 源码剖析之 Renderer(一)
  7. springcloud feign 服务调用其他服务_微服务实战——SpringCloud与Feign集成
  8. 筒灯智能驱动芯片作用_如然之光,魅族 Lipro 智能家居发布首期健康照明系列--智能设备 -...
  9. 连接真机开发安卓(Android)移动app MUI框架 反馈意见、忘记密码、登录、底部选项卡、联系我们、导航等页面代码可拿——混合式开发(六)
  10. Spring中@Async