当前位置: 首页 > news >正文

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等。

特性

异步非阻塞:基于事件驱动模型,支持高并发连接。

高性能:优化了网络通信,资源利用率高。

核心组件

  1. Channel:网络通信的管道,支持多种I/O操作。
  2. EventLoop:事件循环,处理I/O事件。
  3. ChannelHandler:处理I/O事件或拦截操作。
  4. ChannelPipeline:包含多个ChannelHandler,处理入站和出站事件。
  5. ByteBuf:高效的字节容器,优于JDK的ByteBuffer

相关文章:

Spingboot整合Netty,简单示例

Netty介绍在文章末尾 Netty介绍 项目背景 传统socket通信&#xff0c;有需要自身管理整个状态&#xff0c;业务繁杂等问题。 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%就触发报警&#xff0c;这个值怎么填看指标的值显示 这里要设置一下报警条件 这边随便配置下 配置标签和通知&#xff0c;选择你的邮件 看下告警…...

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提供了两种发送来保证发送者的可靠性&#xff0c;第一种叫发送者重连&#xff0c;第二种…...

K8S中Service详解(一)

Service介绍 在Kubernetes中&#xff0c;Service资源解决了Pod IP地址不固定的问题&#xff0c;提供了一种更稳定和可靠的服务访问方式。以下是Service的一些关键特性和工作原理&#xff1a; Service的稳定性&#xff1a;由于Pod可能会因为故障、重启或扩容而获得新的IP地址&a…...

Effective C++读书笔记——item23(用非成员,非友元函数取代成员函数)

一、主要观点&#xff1a; 在某些情况下&#xff0c;使用 non-member、non-friend 函数来替换 member 函数可以增强封装性和可扩展性&#xff0c;提供更好的软件设计。 二、详细解释&#xff1a; 封装性&#xff1a; 类成员函数的封装性考量&#xff1a;成员函数可以访问类的…...

云原生前端开发:打造现代化高性能的用户体验

引言&#xff1a;前端开发的新风向 在过去的几年中&#xff0c;前端开发领域经历了快速的演变&#xff0c;从早期的静态网页到如今复杂的单页应用&#xff08;SPA&#xff09;&#xff0c;再到微前端架构和渐进式Web应用&#xff08;PWA&#xff09;&#xff0c;前端技术一直处…...

循环队列(C语言版)

循环队列(C语言版&#xff09; 1.简单介绍循环队列2.使用何种结构来实现3.基本结构4.初始化5.判空判满6.向循环队列插入一个元素7.从循环队列中删除一个元素8.获取队头队尾元素9.释放空间10.完整代码 &#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#…...

考研408笔记之数据结构(五)——图

数据结构&#xff08;五&#xff09;——图 1. 图的基本概念 1.1 图的定义 1.2 有向图和无向图 在有向图中&#xff0c;使用圆括号表示一条边&#xff0c;圆括号里元素位置互换没有影响。 在无向图中&#xff0c;使用尖括号表示一条边&#xff0c;尖括号里元素位置互换则表示…...

没有公网IP实现seafile本地IP访问和虚拟局域网IP同时访问和上传文件

前言 Ubuntu 24.04 LTSDocker 安装 seafileOpenWrtTailscale Ubuntu 24.04 LTS 通过 docker desktop 安装 seafile 搭建个人网盘中&#xff0c;已经实现了本地局域网放问Ubuntu IP来访问Seafile&#xff0c;以及通过 Ubuntu 的 Tailscale IP 访问Seafile。但是&#xff0c;文…...

【Hadoop面试题2025】

文章目录 简单题故障及相应的处理方法中等难度高难度小文件小文件的产生小文件问题的影响小文件治理方案推荐方案 冷文件冷文件的产生冷文件问题的影响冷文件治理方案推荐方案 简单题 一、基础概念类 什么是Hadoop&#xff1f; 答案&#xff1a;Hadoop是一个开源的分布式计算框…...

2000-2010年各省第三产业就业人数数据

2000-2010年各省第三产业就业人数数据 1、时间&#xff1a;2000-2010年 2、来源&#xff1a;统计年鉴、各省年鉴 3、指标&#xff1a;行政区划代码、地区、年份、第三产业就业人员数&#xff08;万人&#xff09; 4、范围&#xff1a;31省 5、指标解释&#xff1a;第三产业…...

第十一讲 多线程

多线程是提升程序性能非常重要的一种方式&#xff0c;也是Java编程中的一项重要技术。在程序设计中&#xff0c;多线程就是指一个应用程序中有多条并发执行的线索&#xff0c;每条线索都被称作一个线程&#xff0c;它们会交替执行&#xff0c;彼此间可以进行通信。 1. 进程与线…...

VUE之路由Props、replace、编程式路由导航、重定向

目录 1、路由_props的配置 2、路由_replaces属性 3、编程式路由导航 4、路由重定向 1、路由_props的配置 1&#xff09;第一种写法&#xff0c;将路由收到的所有params参数作为props传给路由组件 只能适用于params参数 // 创建一个路由器&#xff0c;并暴露出去// 第一步…...

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

论文地址&#xff1a;Multi-Modal Disordered Representation Learning Network for Description-Based Person Search 代码地址&#xff1a;未开源&#xff08;2025.01.22&#xff09; bib引用&#xff1a; inproceedings{yang2024multi,title{Multi-Modal Disordered Repres…...

小哆啦解题记:加油站的奇幻冒险

小哆啦解题记&#xff1a;加油站的奇幻冒险 小哆啦开始力扣每日一题的第十三天 https://leetcode.cn/problems/gas-station/description/ 在环形道路上&#xff0c;矗立着一串加油站&#xff0c;宛如等待挑战的谜题。这条路上的每个加油站都有一桶汽油&#xff0c;而开车到下一…...

【前端】CSS实战之音乐播放器

目录 播放器背景旋转音乐封面按钮进度条音量调节音乐信息按钮的效果JavaScript部分播放和暂停音乐切换音乐信息进度条 音量调节避免拖拽时的杂音音量调节条静音和解除静音 自动下一首实现一个小效果最终效果 播放器背景 <div class"play_box"></div>设置…...

Games104——渲染中光和材质的数学魔法

原文链接 渲染方程及挑战 挑战 对于任一给定方向如何获得radiance–阴影 对于光源和表面shading的积分运算&#xff08;蒙特卡洛积分&#xff09; 对于反射光多Bounce的无限递归计算 基础光照解决方案 Blinn-Phong模型&#xff1a; 简化阴影 最常见的处理方式就是Shadow M…...

impala增加字段,hsql查不到数据

impala增加字段&#xff0c;插入数据后直接查看文件有值&#xff0c;impala查询是有值的&#xff0c;但是hsq查出来就没有值&#xff01; Parquet格式的表&#xff0c;在重命名表的列名&#xff0c;或新增列名后&#xff0c;查询重名的列数据时显示当前列所有值为NULL。 原因&a…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

【工具教程】多个条形码识别用条码内容对图片重命名,批量PDF条形码识别后用条码内容批量改名,使用教程及注意事项

一、条形码识别改名使用教程 打开软件并选择处理模式&#xff1a;打开软件后&#xff0c;根据要处理的文件类型&#xff0c;选择 “图片识别模式” 或 “PDF 识别模式”。如果是处理包含条形码的 PDF 文件&#xff0c;就选择 “PDF 识别模式”&#xff1b;若是处理图片文件&…...

性能优化中,多面体模型基本原理

1&#xff09;多面体编译技术是一种基于多面体模型的程序分析和优化技术&#xff0c;它将程序 中的语句实例、访问关系、依赖关系和调度等信息映射到多维空间中的几何对 象&#xff0c;通过对这些几何对象进行几何操作和线性代数计算来进行程序的分析和优 化。 其中&#xff0…...

更新 Docker 容器中的某一个文件

&#x1f504; 如何更新 Docker 容器中的某一个文件 以下是几种在 Docker 中更新单个文件的常用方法&#xff0c;适用于不同场景。 ✅ 方法一&#xff1a;使用 docker cp 拷贝文件到容器中&#xff08;最简单&#xff09; &#x1f9f0; 命令格式&#xff1a; docker cp <…...

C++ 使用 ffmpeg 解码 rtsp 流并获取每帧的YUV数据

一、简介 FFmpeg 是一个‌开源的多媒体处理框架‌&#xff0c;非常适用于处理音视频的录制、转换、流化和播放。 二、代码 示例代码使用工作线程读取rtsp视频流&#xff0c;自动重连&#xff0c;支持手动退出&#xff0c;解码并将二进制文件保存下来。 注意&#xff1a; 代…...

如何用 HTML 展示计算机代码

原文&#xff1a;如何用 HTML 展示计算机代码 | w3cschool笔记 &#xff08;请勿将文章标记为付费&#xff01;&#xff01;&#xff01;&#xff01;&#xff09; 在编程学习和文档编写过程中&#xff0c;清晰地展示代码是一项关键技能。HTML 作为网页开发的基础语言&#x…...