netty服务器监听和接收数据

1.pom依赖

        <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><!-- 根据需要选择版本 --><version>4.1.86.Final</version> </dependency>

2.配置属性

application.properties

#启动端口
server.port=8088
server.servlet.context-path=/rxtxcommon
#logging.level.web=DEBUGnetty.server.port=8023
//根据实际情况分配
netty.server.bossThreads=1
//根据实际情况分配
netty.server.workerThreads=4

3.创建netty服务器

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
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.stream.ChunkedWriteHandler;
import lombok.extern.slf4j.Slf4j;import javax.annotation.PreDestroy;
import java.net.InetSocketAddress;import java.util.Objects;
import java.util.concurrent.TimeUnit;@Slf4j
public class NettyServer {private Integer port;private Integer boosThreads = 1;private Integer workerThreads;private Channel channel;private EventLoopGroup bossGroup;private EventLoopGroup workerGroup;public NettyServer(Integer port, Integer boosThreads, Integer workerThreads) throws InterruptedException{this.port = port;this.boosThreads = boosThreads;this.workerThreads = workerThreads;this.init();}private void init() throws InterruptedException {//1.创建一个服务端的引导类ServerBootstrap bootstrap = new ServerBootstrap();//2.创建反应器事件轮询组//boss轮询组(负责处理父通道:连接/接收监听(如NioServerSocketChannel))bossGroup = new NioEventLoopGroup(boosThreads);//workerGroup轮询组(负责处理子通道:读/写监听(如NioSocketChannel))if(Objects.nonNull(this.workerThreads) && this.workerThreads > 0){workerGroup= new NioEventLoopGroup(this.workerThreads);}else{//线程数默认为cpu核心数的2倍workerGroup = new NioEventLoopGroup();}//3.设置父子轮询组bootstrap.group(bossGroup, workerGroup);//4.设置传输通道类型,Netty不仅支持Java NIO,也支持阻塞式的OIObootstrap.channel(NioServerSocketChannel.class);//5.设置监听端口bootstrap.localAddress(new InetSocketAddress(this.port));//6.设置通道参数bootstrap.option(ChannelOption.SO_KEEPALIVE, true);bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);//7.装配子通道的Pipeline流水线bootstrap.childHandler(new ChannelInitializer<SocketChannel>(){@Overrideprotected void initChannel(SocketChannel channel) throws Exception {ChannelPipeline pipeline = channel.pipeline();//添加对byte数组的编解码,是由netty提供的//        pipeline.addLast(new ByteArrayDecoder()); //入站//        pipeline.addLast(new ByteArrayEncoder()); //出站pipeline.addLast("http-codec", new HttpServerCodec());pipeline.addLast("aggregator", new HttpObjectAggregator(65536));//负责WebSocket协议相关的握手处理和数据帧的编解码。当你创建一个WebSocket服务器时,这个处理器会处理来自客户端的WebSocket握手请求,完成握手过程,并在握手成功后,将连接转换为WebSocket连接。参数 "/websocket" 通常代表WebSocket连接的路径pipeline.addLast(new WebSocketServerProtocolHandler("/websocket"));pipeline.addLast("http-chunked", new ChunkedWriteHandler());//添加自定义处理器 pipeline.addLast(new SocketInboundHandler());}});//8.开始绑定端口,并通过调用sync()同步方法阻塞直到绑定成功ChannelFuture future = bootstrap.bind().sync();log.info("服务端启动成功,监听端口:{}", this.port);channel=future.channel();//9.自我阻塞,直到监听通道关闭ChannelFuture closeFuture = future.channel().closeFuture();closeFuture.sync();log.info("服务端已停止运行");//10.释放所有资源,包括创建的反应器线程workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();log.info("已释放服务端占用资源");}@PreDestroypublic void stop() {System.out.println("关闭netty服务器");if (channel != null) {channel.close();}if (workerGroup != null) {workerGroup.shutdownGracefully(0, 10, TimeUnit.SECONDS);}if (bossGroup != null) {bossGroup.shutdownGracefully(0, 10, TimeUnit.SECONDS);}}}

4.建立监听和响应

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;@Slf4j
public class SocketInboundHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
//主要用于处理接收数据的某些事件。它支持泛型的消息处理,并在默认情况下,当消息处理完毕后会自动释放。/*** 读取客户端发送来的消息*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame textWebSocketFrame) throws Exception {ctx.channel().writeAndFlush(new TextWebSocketFrame("服务器返回"+textWebSocketFrame.text()));}/*** 接入客户端*/@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {log.info("新客户端连接:{}", ctx.channel().id().asShortText());}/*** 断开客户端*/@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {log.info("客户端连接断开:{}", ctx.channel().id().asShortText());}/*** 异常处理*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {log.info("客户端异常:{}", cause.getMessage(), cause);ctx.channel().close();}
}

5.创建启动器

@Slf4j
@Component
public class NettyStarter implements ApplicationRunner {
//ApplicationRunner 实现这个接口,不会阻断springboot启动应用线程的阻塞@Value("${netty.server.port}")private Integer port;@Value("${netty.server.bossThreads}")private Integer bossThreads;@Value("${netty.server.workerThreads:-1}")private Integer workerThreads;@Overridepublic void run(ApplicationArguments args) throws Exception {try{new NettyServer(port, bossThreads, workerThreads);}catch (Exception e){log.info("服务端启动异常:{}", e.getMessage(), e);}}
}

6.前端static下页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WebSocket Client</title><script src="sockt.js"></script>
</head>
<body>
<h1>WebSocket Client</h1>
<button onclick="connect()">Connect1</button>
<button onclick="sendMessage()">Send Message1</button>
<button onclick="connect2()">Connect2</button>
<button onclick="sendMessage2()">Send Message2</button>
<ul id="messages"></ul></body>
</html>

7.前端js


var ws;
var ws2;
function connect() {debugger// 假设你的WebSocket服务器运行在以下URL,并且WebSocket的端点是"/websocket"var wsUrl = 'ws://localhost或者ip地址:8023/websocket';// 创建WebSocket连接ws = new WebSocket(wsUrl);// 监听连接打开事件ws.onopen = function(event) {console.log('WebSocket连接已打开');displayMessage('Connected to server.');};// 监听从服务器接收到的消息事件ws.onmessage = function(event) {console.log('收到来自服务器的消息:', event.data);displayMessage('Received: ' + event.data);};// 监听连接关闭事件ws.onclose = function(event) {console.log('WebSocket连接已关闭');displayMessage('Connection closed.');};// 监听连接错误事件ws.onerror = function(error) {console.error('WebSocket发生错误', error);displayMessage('WebSocket Error: ' + error.message);};
}function connect2() {debugger// 假设你的WebSocket服务器运行在以下URL,并且WebSocket的端点是"/websocket"var wsUrl = 'ws://localhost或者ip地址:8023/websocket';// 创建WebSocket连接ws2 = new WebSocket(wsUrl);// 监听连接打开事件ws2.onopen = function(event) {console.log('WebSocket连接已打开');displayMessage('Connected to server.');};// 监听从服务器接收到的消息事件ws2.onmessage = function(event) {console.log('收到服务器2信息:', event.data);displayMessage('收到服务器2信息: ' + event.data);};// 监听连接关闭事件ws2.onclose = function(event) {console.log('WebSocket连接已关闭');displayMessage('Connection closed.');};// 监听连接错误事件ws2.onerror = function(error) {console.error('WebSocket发生错误', error);displayMessage('WebSocket Error: ' + error.message);};
}function sendMessage() {if (ws.readyState === WebSocket.OPEN) {var message = prompt('请输入要发送的消息:');ws.send(message);displayMessage('Sent: ' + message);} else {displayMessage('WebSocket连接未打开,请先连接。');}
}
function sendMessage2() {if (ws2.readyState === WebSocket.OPEN) {var message = prompt('请输入要发送的消息:');ws2.send(message);displayMessage('Sent: ' + message);} else {displayMessage('WebSocket连接未打开,请先连接。');}
}
function displayMessage(message) {var messagesList = document.getElementById('messages');var li = document.createElement('li');li.textContent = message;messagesList.appendChild(li);
}

8.注意异常问题

1.不用InitializingBean接口初始化–阻塞springboot应用线程启动创建
2.不用 @PostConstruct执行初始化方法建立接口绑定–阻塞springboot应用线程启动创建

在类的方法上使用@PostConstruct注解,可以确保该方法在依赖注入完成后立即执行。这也可以作为启动Netty服务器的一个点。但是,需要注意的是,@PostConstruct在单例Bean的初始化阶段执行,可能早于ApplicationRunner或CommandLineRunner。
3.用异步注解@Async–没有尝试过
3.创建netty过程中,启动时用ApplicationRunner --正确
4.创建netty过程中,启动时用CommandLineRunner–正确
无论选择哪种方式,都需要确保Netty服务器的启动不会阻塞Spring Boot的主线程。如果需要,可以考虑使用线程池来管理Netty的IO操作,以避免阻塞。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/742835.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零开始,一步步构建服务网格istio

一、环境情况 环境&#xff1a;Ubuntu20.04 机器数量&#xff1a;单机1台 IP&#xff1a;10.9.2.83 二、准备知识 为什么使用 Istio&#xff1f; Istio提供了一种更高级别的服务网格解决方案&#xff0c;它可以简化和加强 Kubernetes 集群中的服务间通信、流量管理、安全…

Git操作指南:子模块、用户名修改和Subtree

引言 在软件开发中&#xff0c;版本控制是一个至关重要的环节。Git 作为目前最流行的版本控制工具之一&#xff0c;提供了丰富的功能和灵活的操作方式。本文将介绍一些常用的 Git 操作&#xff0c;包括管理子模块、修改用户名、使用 Git Subtree 合并项目以及其他一些常见操作…

基于R语言APSIM模型应用

随着数字农业和智慧农业的发展&#xff0c;基于过程的农业生产系统模型在模拟作物对气候变化的响应与适应、农田管理优化、作物品种和株型筛选、农田固碳和温室气体排放等领域扮演着越来越重要的作用。APSIM (Agricultural Production Systems sIMulator)模型是世界知名的作物生…

鸿蒙开发之MPChart图表开发

一、简介 随着移动应用的不断发展,数据可视化成为提高用户体验和数据交流的重要手段之一,因此需要经常使用图表,如折线图、柱形图等。OpenHarmony提供了一个强大而灵活的图表库是实现这一目标的关键。 在 ohpm 中心仓(https://ohpm.openharmony.cn/)中,汇聚了众多开发者…

ubuntu如何添加快捷方式到收藏夹、桌面

一、背景 有时候单独下载的软件包需要在特定路径里启动&#xff0c;这样使用起来非常不方便。因此需要在桌面和收藏夹里创建启动快捷方式。 二、具体步骤 这里以下载的zotero软件&#xff08;一款用于文献管理的软件&#xff09;为例。官网地址: Zotero | Your personal res…

python控制语句-2.1

目录 while循环 while循环练习-1 while 循环 - break 语法 while 循环 - continue 语法 while 循环 - else 语法 while循环练习-2 while循环 while循环练习-1 求1到n的交错和输入正整数 n&#xff0c;求 1 到 n 的交错和&#xff1a;即 -12-34-56-7...((-1)^n)*nn eval(…

shell脚本中数组元素赋值

在Shell&#xff08;特别是Bash&#xff09;脚本中定义和赋值数组有几种不同的方法。基本的数组赋值语句如下&#xff1a; # 无索引数组的赋值 array_name(element1 element2 element3)其中 element1 element2 element3 是数组 array_name 的元素。 如果你想要更新现有数组的…

【gpt实践】同时让chatgpt和claude开发俄罗斯方块

最近chatgpt和claude都在使用&#xff0c;其实大部分日常使用场景表现都没有相差太多&#xff0c;想搞一个有趣的小实验&#xff0c;如果同时让chatgpt和claude开发俄罗斯方块谁会表现的更好呢&#xff0c;说干就干&#xff01; prompt 我选择了用英文描述&#xff0c;毕竟英…

Unity中计算两个三维坐标点的各种方法

1、 根据勾股定理计算两点的距离 /// <summary>/// 根据勾股定理计算两点的距离/// </summary>/// <param name"point1"></param>/// <param name"point2"></param>/// <returns></returns>private float…

《如何使用C语言去下三子棋?》

目录 一、环境配置 二、功能模块 1.打印菜单 2.初始化并打印棋盘 3、行棋 3.1玩家行棋 3.2电脑行棋 4、判断是否和棋 5.判赢 三、代码实现 1、test.c文件 2、game.c文件 3、game.h文件 一、环境配置 本游戏用到三个文件&#xff0c;分别是两个源文件test.c game.c 和…

JWT令牌校验是什么东西?举个例子

JWT&#xff08;JSON Web Token&#xff09;令牌校验是验证JWT令牌的有效性和真实性的过程。JWT是一种用于在网络应用间安全传递信息的开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它由三部分组成&#xff1a;头部&#xff08;header&#xff09;、载荷&#xff08;p…

zabbix-server-pgsql docker镜像备忘

Environment Variables 基本变量 When you start the zabbix-server-pgsql image, you can adjust the configuration of the Zabbix server by passing one or more environment variables on the docker run command line. DB_SERVER_HOST This variable is IP or DNS nam…

cad转shp再转3dtiles生成白模

1、准备CAD数据 2、arcgis中添加cad数据 添加面 cad中的标高字段是能带进arcgis中的&#xff0c;如果这个数据是建筑高度&#xff0c;可以直接用了 3、转shp 4、shp转3dtiles白模 cesiumlab中shp转3dtiles白模效果一

【智能硬件、大模型、LLM 智能音箱】Emo:基于树莓派 4B DIY 能笑会动的桌面机器人

简介 Emo 是一款个人伴侣机器人,集时尚与创新于一身。他的诞生离不开最新的树莓派 4 技术和先进的设计。他不仅仅是一款机器人,更是一个活生生的存在。与其他机器人不同,他拥有独特的个性和情感,能够俘获你的心灵。 硬件部分 – 树莓派 4B – 微雪 2 英寸 IPS LCD 显示屏…

Spring Cloud Alibaba微服务从入门到进阶(三)

Spring Cloud Alibaba是spring Cloud的子项目 Spring Cloud Alibaba的主要组件&#xff08;红框内是开源的&#xff09; Spring Cloud是快速构建分布式系统的工具集&#xff0c; Spring Cloud提供了很多分布式功能 Spring Cloud常用子项目 项目整合 Spring Cloud Alibaba …

搭建项目后台系统基础架构

任务描述 1、了解搭建民航后端框架 2、使用IDEA创建基于SpringBoot、MyBatis、MySQL、Redis的Java项目 3、以原项目为参照搭建项目所涉及到的各个业务和底层服务 4、以原项目为例&#xff0c;具体介绍各个目录情况并参照创建相关文件夹 1、创建项目后端 BigData-KongGuan …

海豚调度系列之:任务类型——SQL节点

海豚调度系列之&#xff1a;任务类型——SQL节点 一、SQL节点二、创建任务三、任务参数四、任务样例五、运行该任务成功之后在hive中查询结果六、使用前置sql和后置sql示例 一、SQL节点 SQL任务类型&#xff0c;用于连接数据库并执行相应SQL。 二、创建任务 点击项目管理-项…

JVM,GC算法,垃圾回收器,类加载器,进行线上JVM性能调优。

JVM&#xff08;Java Virtual Machine&#xff0c;Java虚拟机&#xff09;是Java程序的运行环境&#xff0c;它在操作系统上提供了一个抽象层&#xff0c;使得Java程序可以独立于硬件平台运行。JVM有自己的指令集和内存管理机制&#xff0c;它负责将Java字节码转换为机器码并执…

清廉机关建设宣传稿件怎样联系媒体投稿发表?

在推进清廉机关建设的伟大征程中,我们深知信息宣传的重要性。如何将清廉机关建设的成果和理念广泛传播,让更多人了解并参与到这一伟大事业中来,成为我们面临的重要课题。 过去,我们或许曾经历过联系媒体投稿的种种心酸。一家家媒体的联系,一次次的等待与回复,其中的艰辛与不易…

mapperXML标签总结

MyBatis 的真正强大在于它的语句映射&#xff0c;这是它的魔力所在。由于它的异常强大&#xff0c;映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比&#xff0c;省掉了将近 95% 的代码。MyBatis 致力于减少使用成本&#xff0c;让用户能更专注于…