发布时间:2026/8/29 23:16:39
Netty入门(二)时间服务器及客户端 在这个例子中我在服务器和客户端连接被创立时发送一个消息然后在客户端解析收到的消息并输出。并且在这个项目中我使用 POJO 代替 ByteBuf 来作为传输对象。一、服务器实现1. 首先我们自定义传输数据对象1 package com.coder.client; 2 3 import java.util.Date; 4 5 /** 6 * 自定义时间数据类 7 * author Coder 8 * 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 MessageToByteEncoderTime { 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 ChannelInitializerSocketChannel() { 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, ListObject 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 Coder 9 * 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 ChannelInitializerSocketChannel() { 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 程序的可以通过点击来切换不同程序的控制台输出窗口。

相关新闻

2026/8/27 16:13:27

Python DDD架构实战:从业务混乱到领域清晰的技术演进

Python DDD架构实战:从业务混乱到领域清晰的技术演进 【免费下载链接】python-ddd Python DDD example 项目地址: https://gitcode.com/gh_mirrors/py/python-ddd 在复杂业务系统开发中,技术团队常面临业务逻辑分散、代码难以维护、新需求开发举…

2026/8/29 23:13:31

HCI_HARDWARE_ERROR_EVENT 与 ISR 延迟误差:蓝牙控制器异常排查实录

HCI_HARDWARE_ERROR_EVENT 与 ISR 延迟误差:一次完整的蓝牙控制器异常排查实录最近在调试一款基于低功耗蓝牙芯片的物联网模组时,遇到了一个非常棘手的稳定性问题。设备在长时间运行后,会随机出现连接断开,并且在调试日志中频繁看…

2026/8/29 23:13:31

校招在线编程考试全攻略:从备考策略到避坑指南

2020年春招那阵子,很多企业的笔试都搬到了线上,vivo2020届春季校园招聘在线编程考试就是我当时印象很深的一场。身边不少学弟学妹第一次接触在线编程平台,有人开考十几分钟还在跟编辑器较劲,有人把本地IDE里跑得好好的代码原样粘上…

2026/8/29 23:13:31

基于Neo4j的中医药知识图谱问答系统设计与实现

简介:知识图谱以图结构组织数据,将实体与关系映射为节点和边,为医疗健康领域的复杂信息检索提供了直观的建模方式。Neo4j作为成熟的图数据库引擎,能够高效执行多跳关系查询,并借助Cypher语言灵活处理症状、疾病、中药等…

2026/8/29 23:13:31

推荐系统驱动的传感器子集选择:干扰鲁棒建模与工程实践

这次我们来看一个交叉研究方向:A Recommendation System Approach for Interference-Robust Sensor Subset Selection。简单说,就是在大规模传感器网络里做“传感器子集选择”,但用的不是传统贪心、穷举或凸优化,而是把推荐系统的…

2026/8/29 23:13:31

WeLive V7.1源码部署与定制化改造实战指南

简介:WeLive是一款面向中小企业的轻量级PHP客服系统,其V7.1版本采用纯PHP单体架构,强调可读性、可调试性与深度定制能力。它不依赖现代框架抽象,核心逻辑直写于class.*.php文件中,数据库操作基于PDO原生封装&#xff0…

2026/8/29 23:08:31

自然场景OCR实战:YOLOv3+CTPN+CRNN检测识别流水线搭建与优化

简介:OCR(光学字符识别)是计算机视觉领域将图像文字转换为机器可读文本的关键技术。其核心原理在于通过深度学习模型模拟人类视觉与认知过程,实现从像素到语义的映射。该技术的核心价值在于极大地提升了信息数字化与结构化的效率&…

2026/8/29 21:30:11

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/28 16:16:21

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/28 16:16:22

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/29 0:01:10

etc目录下的profile.d文件目录设置环境变量和全局脚本shell

一、设置环境变量etc目录下的profile.d文件目录 /etc/profile.d1、编写 vi test.sh文件内容# jdk变量 export ZHK_HOME/root export PATH$PATH:$ZHK_HOME/test # 可以取出来ZHK_HOME变量给ZZZ_HOME赋值 export ZZZ_HOME${ZHK_HOME}/test2、刷新 执行source /etc/profile 命令使…

2026/8/29 0:01:10

【JavaScript】内存管理-垃圾回收机制-内存泄露

内存管理 C 语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()。 而 JavaScript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。 整…

2026/8/29 0:01:10

Labgrid-MCP:为嵌入式硬件实验室接入AI Agent操控能力

Labgrid-MCP 的目标是把 MCP(Model Context Protocol)能力延伸到真实嵌入式硬件实验室:AI Agent 通过一个标准化的 MCP Server,就能查看目标板状态、控制上电断电、复位开发板、读取串口日志,甚至执行镜像刷写。对于经…

2026/8/28 16:16:48

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/28 16:16:50

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/28 11:06:45

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…