Spingboot整合Netty,简单示例
Netty介绍在文章末尾 Netty介绍
项目背景
传统socket通信,有需要自身管理整个状态,业务繁杂等问题。
pom.xml
<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.117.Final</version>
</dependency>
代码
封装Netty的服务类
package com.example.server;import com.example.exception.ServiceException;
import com.example.handler.NettyServerInitializer;
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;
import lombok.extern.slf4j.Slf4j;@Slf4j
public class NettyServer {// 用于处理连接请求的线程组private EventLoopGroup bossGroup;// 用于处理I/O操作的线程组private EventLoopGroup workerGroup;// 服务器private ChannelFuture channelFuture;/*** 启动 Netty 服务端** @param port 监听的端口*/public void start(int port) {bossGroup = new NioEventLoopGroup(); // 初始化bossGroupworkerGroup = new NioEventLoopGroup(); // 初始化workerGrouptry {ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // 使用NIO传输.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {// 添加编解码器和处理器ch.pipeline().addLast(new NettyServerInitializer());}}).option(ChannelOption.SO_BACKLOG, 128) // 设置TCP参数.childOption(ChannelOption.SO_KEEPALIVE, true);// 绑定端口并启动服务器channelFuture = bootstrap.bind(port).sync();log.info("Netty 服务端启动成功,监听端口: {}", port);} catch (InterruptedException e) {log.error("Netty 服务端启动失败,端口: {}, 异常: {}", port, e.getMessage(), e);throw new ServiceException("Netty 服务端启动异常");} catch (Exception e) {log.error("绑定端口时发生异常: {}", e.getMessage(), e);throw new ServiceException("端口绑定异常");}}/*** 停止 Netty 服务端*/public void stop() {if (channelFuture != null) {channelFuture.channel().close();}if (bossGroup != null) {bossGroup.shutdownGracefully();}if (workerGroup != null) {workerGroup.shutdownGracefully();}System.out.println("Netty 服务端已关闭");}}
封装Netty服务的管理类
用来创建和销毁多个Netty
package com.example.server;import com.example.exception.ServiceException;
import org.springframework.stereotype.Service;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Service
public class NettyServerManager {private final ConcurrentHashMap<Integer, NettyServer> nettyServers = new ConcurrentHashMap<>();/*** 启动 Netty 服务端** @param port 监听的端口*/public void startNettyServer(int port) {if (nettyServers.containsKey(port)) {throw new ServiceException("端口 " + port + " 已被占用");}NettyServer nettyServer = new NettyServer();nettyServer.start(port);nettyServers.put(port, nettyServer);}/*** 停止 Netty 服务端** @param port 监听的端口*/public void stopNettyServer(int port) {NettyServer nettyServer = nettyServers.get(port);if (nettyServer != null) {nettyServer.stop();nettyServers.remove(port);}}/*** 获取所有 Netty 服务端实例*/public Map<Integer, NettyServer> getNettyServers() {return nettyServers;}
}
NettyServer的初始化
package com.example.handler;import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;public class NettyServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) {ch.pipeline()// HTTP 编解码器:支持 HTTP 请求和响应.addLast(new HttpServerCodec())// 聚合 HTTP 消息,避免处理分块的 HTTP 请求.addLast(new HttpObjectAggregator(65536))// WebSocket 协议处理器,确保路径 `/websocket` 处理 WebSocket 握手和控制帧.addLast(new WebSocketServerProtocolHandler("/websocket"))// 字符串解码器,将字节流解析为字符串.addLast(new StringDecoder(CharsetUtil.UTF_8))// 字符串编码器,将字符串转换为字节流.addLast(new StringEncoder(CharsetUtil.UTF_8))// 自定义消息处理器,用于处理业务逻辑.addLast(new WebSocketFrameHandler());}
}
handler处理器类
用来处理具体的消息
package com.example.handler;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;@Slf4j
@Component
public class WebSocketFrameHandler extends ChannelInboundHandlerAdapter {@Resourceprivate UserService userService;@PostConstructpublic void init() {webSocketFrameHandler = this;}/*** 当 Channel 变为活跃状态(连接建立)时调用*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {log.warn("{} 已连接", ctx.channel().remoteAddress());}/*** 当 Channel 变为不活跃状态(连接关闭)时调用*/@Overridepublic void channelInactive(ChannelHandlerContext ctx) {log.warn("{} 已断开", ctx.channel().remoteAddress());}/*** 当从 Channel 中读取到数据时调用*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {}/*** 当一次数据读取完成时调用*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {// log.info("Channel 数据读取完成");ctx.flush();}/*** 当处理过程中发生异常时调用*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {log.error("处理过程中发生异常,连接关闭: {}", cause.getMessage(), cause);ctx.close();}
}
消息传递实体
这里分享一个我用来消息传递的实体,这个实体需要被序列化传递。因为Websocket传递都是文本的形式
Netty介绍
Netty 是一个异步事件驱动的网络应用框架,主要用于快速开发高性能、高可靠性的网络服务器和客户端。它简化了TCP、UDP等协议的编程,广泛应用于WebSocket等。
特性
异步非阻塞:基于事件驱动模型,支持高并发连接。
高性能:优化了网络通信,资源利用率高。
核心组件
- Channel:网络通信的管道,支持多种I/O操作。
- EventLoop:事件循环,处理I/O事件。
- ChannelHandler:处理I/O事件或拦截操作。
- ChannelPipeline:包含多个ChannelHandler,处理入站和出站事件。
- ByteBuf:高效的字节容器,优于JDK的ByteBuffer
相关文章:
Spingboot整合Netty,简单示例
Netty介绍在文章末尾 Netty介绍 项目背景 传统socket通信,有需要自身管理整个状态,业务繁杂等问题。 pom.xml <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.117.F…...
grafana新增email告警
选择一个面板 比如cpu 新增一个临界点表达式 input选A 就是A的值达到某个临界点 触发告警 我这边IS ABOVE0.15就是cpu大于0.15%就触发报警,这个值怎么填看指标的值显示 这里要设置一下报警条件 这边随便配置下 配置标签和通知,选择你的邮件 看下告警…...
Github 2025-01-20 开源项目周报 Top15
根据Github Trendings的统计,本周(2025-01-20统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10Rust项目2TypeScript项目1C++项目1Jupyter Notebook项目1Go项目1Tabby: 自托管的AI编码助手 创建周期:310 天开发语言:Rust协议类…...
【Rabbitmq】Rabbitmq高级特性-发送者可靠性
Rabbitmq发送者可靠性 发送者重连发送者确认1.开启确认机制2.ReturnCallback3.ConfirmCallback MQ的可靠性数据持久化交换机持久化队列持久化消息持久化 Lazy Queue 总结其他文章 Rabbitmq提供了两种发送来保证发送者的可靠性,第一种叫发送者重连,第二种…...
K8S中Service详解(一)
Service介绍 在Kubernetes中,Service资源解决了Pod IP地址不固定的问题,提供了一种更稳定和可靠的服务访问方式。以下是Service的一些关键特性和工作原理: Service的稳定性:由于Pod可能会因为故障、重启或扩容而获得新的IP地址&a…...
Effective C++读书笔记——item23(用非成员,非友元函数取代成员函数)
一、主要观点: 在某些情况下,使用 non-member、non-friend 函数来替换 member 函数可以增强封装性和可扩展性,提供更好的软件设计。 二、详细解释: 封装性: 类成员函数的封装性考量:成员函数可以访问类的…...
云原生前端开发:打造现代化高性能的用户体验
引言:前端开发的新风向 在过去的几年中,前端开发领域经历了快速的演变,从早期的静态网页到如今复杂的单页应用(SPA),再到微前端架构和渐进式Web应用(PWA),前端技术一直处…...
循环队列(C语言版)
循环队列(C语言版) 1.简单介绍循环队列2.使用何种结构来实现3.基本结构4.初始化5.判空判满6.向循环队列插入一个元素7.从循环队列中删除一个元素8.获取队头队尾元素9.释放空间10.完整代码 🌟🌟hello,各位读者大大们你们好呀&#…...
考研408笔记之数据结构(五)——图
数据结构(五)——图 1. 图的基本概念 1.1 图的定义 1.2 有向图和无向图 在有向图中,使用圆括号表示一条边,圆括号里元素位置互换没有影响。 在无向图中,使用尖括号表示一条边,尖括号里元素位置互换则表示…...
没有公网IP实现seafile本地IP访问和虚拟局域网IP同时访问和上传文件
前言 Ubuntu 24.04 LTSDocker 安装 seafileOpenWrtTailscale Ubuntu 24.04 LTS 通过 docker desktop 安装 seafile 搭建个人网盘中,已经实现了本地局域网放问Ubuntu IP来访问Seafile,以及通过 Ubuntu 的 Tailscale IP 访问Seafile。但是,文…...
【Hadoop面试题2025】
文章目录 简单题故障及相应的处理方法中等难度高难度小文件小文件的产生小文件问题的影响小文件治理方案推荐方案 冷文件冷文件的产生冷文件问题的影响冷文件治理方案推荐方案 简单题 一、基础概念类 什么是Hadoop? 答案:Hadoop是一个开源的分布式计算框…...
2000-2010年各省第三产业就业人数数据
2000-2010年各省第三产业就业人数数据 1、时间:2000-2010年 2、来源:统计年鉴、各省年鉴 3、指标:行政区划代码、地区、年份、第三产业就业人员数(万人) 4、范围:31省 5、指标解释:第三产业…...
第十一讲 多线程
多线程是提升程序性能非常重要的一种方式,也是Java编程中的一项重要技术。在程序设计中,多线程就是指一个应用程序中有多条并发执行的线索,每条线索都被称作一个线程,它们会交替执行,彼此间可以进行通信。 1. 进程与线…...
VUE之路由Props、replace、编程式路由导航、重定向
目录 1、路由_props的配置 2、路由_replaces属性 3、编程式路由导航 4、路由重定向 1、路由_props的配置 1)第一种写法,将路由收到的所有params参数作为props传给路由组件 只能适用于params参数 // 创建一个路由器,并暴露出去// 第一步…...
windows安装ES
1. 下载ES 访问ES官网下载Download Elasticsearch | Elastic 2. 配置环境变量 ES_JAVA_HOME : D:\jdk-17.0.9 ES_HOME : D:\elasticsearch-8.17.1-windows-x86_64\elasticsearch-8.17.1 3. 添加一些ES的配置 <1>关闭ES安全认证 打开elasticsearch-8.17.1\config\e…...
论文速读|Multi-Modal Disordered Representation Learning Network for TBPS.AAAI24
论文地址:Multi-Modal Disordered Representation Learning Network for Description-Based Person Search 代码地址:未开源(2025.01.22) bib引用: inproceedings{yang2024multi,title{Multi-Modal Disordered Repres…...
小哆啦解题记:加油站的奇幻冒险
小哆啦解题记:加油站的奇幻冒险 小哆啦开始力扣每日一题的第十三天 https://leetcode.cn/problems/gas-station/description/ 在环形道路上,矗立着一串加油站,宛如等待挑战的谜题。这条路上的每个加油站都有一桶汽油,而开车到下一…...
【前端】CSS实战之音乐播放器
目录 播放器背景旋转音乐封面按钮进度条音量调节音乐信息按钮的效果JavaScript部分播放和暂停音乐切换音乐信息进度条 音量调节避免拖拽时的杂音音量调节条静音和解除静音 自动下一首实现一个小效果最终效果 播放器背景 <div class"play_box"></div>设置…...
Games104——渲染中光和材质的数学魔法
原文链接 渲染方程及挑战 挑战 对于任一给定方向如何获得radiance–阴影 对于光源和表面shading的积分运算(蒙特卡洛积分) 对于反射光多Bounce的无限递归计算 基础光照解决方案 Blinn-Phong模型: 简化阴影 最常见的处理方式就是Shadow M…...
impala增加字段,hsql查不到数据
impala增加字段,插入数据后直接查看文件有值,impala查询是有值的,但是hsq查出来就没有值! Parquet格式的表,在重命名表的列名,或新增列名后,查询重名的列数据时显示当前列所有值为NULL。 原因&a…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...
如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
