SpringBoot集成Netty實現Ws和Tcp通信

? ? ? ? 本教程將指導你如何在 Spring Boot 項目中集成 Netty,實現 WebSocket 和 TCP 通信。以下是詳細的步驟和代碼示例。??

環境準備

在 你的pom.xml 中添加 Netty 依賴:

<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>5.0.0.Alpha2</version>
</dependency>

Ws通信具體模塊

1.初始服務端代碼

import com.leyting.handler.MsgHandler;
import io.netty.bootstrap.ServerBootstrap;
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 io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;@Slf4j
@Component
public class Init implements ApplicationRunner {public static void serverStart(int port) {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();ServerBootstrap serverBootstrap = new ServerBootstrap();try {serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast();pipeline.addLast(new HttpServerCodec());pipeline.addLast(new ChunkedWriteHandler());pipeline.addLast(new IdleStateHandler(12,12,12, TimeUnit.DAYS));pipeline.addLast(new HttpObjectAggregator(1024*64));pipeline.addLast(new WebSocketServerProtocolHandler("/websocket"));pipeline.addLast(new MsgHandler());}});ChannelFuture channelFuture = serverBootstrap.bind(port).sync();channelFuture.addListener((ChannelFutureListener) channelFuture1 -> {if (channelFuture1.isSuccess()) {log.info("Websocket啟動成功,端口:{}", port);}else {log.warn("Websocket啟動失敗,端口:{}", port);}});channelFuture.channel().closeFuture().sync();} catch (Exception e) {throw new RuntimeException(e);}finally {bossGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}@Overridepublic void run(ApplicationArguments args)  {serverStart(7309);}
}

2.信息處理器

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Slf4j
public class MsgHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {public final static Map<ChannelId, Channel> CHANNEL = new ConcurrentHashMap<>();private final static ChannelGroup channelGroups = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);@Overridepublic void handlerAdded(ChannelHandlerContext ctx){channelGroups.add(ctx.channel());SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");ChannelId id = ctx.channel().id();CHANNEL.put(id, ctx.channel());log.info("客服端:{} 上線了!",id);ctx.channel().writeAndFlush(new TextWebSocketFrame(format.format(new Date()) + " 歡迎你的上線"));}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){cause.printStackTrace();ChannelId id = ctx.channel().id();CHANNEL.remove(id);channelGroups.remove(ctx.channel());log.info("客服端:{} 異常斷開!",id);ctx.close();}@Overridepublic void channelInactive(ChannelHandlerContext ctx){channelGroups.remove(ctx.channel());log.info("客服端:{} 斷開連接!",ctx.channel().id());CHANNEL.remove(ctx.channel().id());ctx.close();}@Overrideprotected void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame textWebSocketFrame) throws Exception {if (!CHANNEL.containsKey(ctx.channel().id())) { CHANNEL.put(ctx.channel().id(), ctx.channel());}String msg = textWebSocketFrame.text();log.info("客服端:{} 發送消息:{}", ctx.channel().id(), msg );ctx.channel().writeAndFlush(new TextWebSocketFrame("服務端收到您發送的信息:" + msg));}
}

3.測試用例?

測試案例
Ws測試用例

WebSocket測試網站http://wstool.js.org/

Tcp通信具體模塊

1.初始服務端代碼

import com.leyting.handler.MsgHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;@Component
@Slf4j
public class Init implements ApplicationRunner {public static void serverStart(int port) {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();ServerBootstrap serverBootstrap = new ServerBootstrap();try {serverBootstrap.group(bossGroup,workerGroup)// 添加通道設置非阻塞.channel(NioServerSocketChannel.class)// 服務端可連接隊列數量.option(ChannelOption.SO_BACKLOG, 128)// 開啟長連接.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)// 流程處理.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {ch.pipeline().addLast(new MsgHandler());}});ChannelFuture channelFuture = serverBootstrap.bind(port).sync();channelFuture.addListener((ChannelFutureListener) channelFuture1 -> {if (channelFuture1.isSuccess()) {log.info("TcpServer啟動成功,端口:{}", port);}else {log.error("TcpServer啟動失敗,端口:{}", port);}});channelFuture.channel().closeFuture().sync();} catch (Exception e) {throw new RuntimeException(e);}finally {bossGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}@Overridepublic void run(ApplicationArguments args)  {serverStart(7311);}
}

2.信息處理器代碼

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Slf4j
public class MsgHandler extends ChannelInboundHandlerAdapter  {public final static Map<ChannelId, Channel> CHANNEL = new ConcurrentHashMap<>();private final static ChannelGroup channelGroups = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);@Overridepublic void handlerAdded(ChannelHandlerContext ctx)  {channelGroups.add(ctx.channel());SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");ctx.channel().writeAndFlush(new TextWebSocketFrame(format.format(new Date()) + " 歡迎你的上線"));ChannelId id = ctx.channel().id();CHANNEL.put(id, ctx.channel());log.info("客服端:{} 上線了!",id);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();channelGroups.remove(ctx.channel());log.info("客服端:{} 異常!",ctx.channel().id());CHANNEL.remove(ctx.channel().id());ctx.close();}@Overridepublic void channelInactive(ChannelHandlerContext ctx)  {channelGroups.remove(ctx.channel());log.info("客服端:{} 斷開連接!",ctx.channel().id());CHANNEL.remove(ctx.channel().id());ctx.close();}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {if (msg instanceof ByteBuf byteBuf) {// 將 ByteBuf 轉換為字符串String message = byteBuf.toString(CharsetUtil.UTF_8);log.info("客服端:{} 發送消息:{}", ctx.channel().id(), message);ctx.channel().writeAndFlush(Unpooled.copiedBuffer("服務端收到您發送的信息:" + message, CharsetUtil.UTF_8));} else {log.info("客服端:{} 發送未知類型的消息:{}", ctx.channel().id(), msg);}}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/897139.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/897139.shtml
英文地址,請注明出處:http://en.pswp.cn/news/897139.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

與中國聯通技術共建:通過obdiag分析OceanBase DDL中的報錯場景

中國聯通軟件研究院&#xff08;簡稱聯通軟研院&#xff09;在全面評估與廣泛調研后&#xff0c;在 2021年底決定采用OceanBase 作為基礎&#xff0c;自研分布式數據庫產品CUDB&#xff08;即China Unicom Database&#xff0c;中國聯通數據庫&#xff09;。目前&#xff0c;該…

機器學習-隨機森林解析

目錄 一、.隨機森林的思想 二、隨機森林構建步驟 1.自助采樣 2.特征隨機選擇 3構建決策樹 4.集成預測 三. 隨機森林的關鍵優勢 ?**(1) 減少過擬合** ?**(2) 高效并行化** ?**(3) 特征重要性評估** ?**(4) 耐抗噪聲** 四. 隨機森林的優缺點 ?優點 ?缺點 五.…

深度集成DeepSeek,智問BI@GPT引領商業智能“深度思考“革命

當下傳統的數據分析工具如同顯微鏡&#xff0c;雖然能幫助我們看到數據的細節&#xff0c;卻難以揭示數據背后的深層規律。億信華辰最新升級的智問BIGPT產品&#xff0c;通過深度集成DeepSeek大模型&#xff0c;首次在商業智能領域實現了"深度思考"功能。這項突破性創…

Mysql安裝方式

方式一&#xff1a;安裝包安裝 下載安裝包 官網直接下載&#xff1a;https://dev.mysql.com/downloads/ 安裝配置 2.1、雙擊剛剛下載好的msi文件&#xff0c;開始安裝MySQL。 2.2、選擇自定義模式Custom安裝 2.3、點擊選擇自己電腦對應的mysql安裝目錄 2.5、繼續點擊下一步&…

unity調用本地部署deepseek全流程

unity調用本地部署deepseek全流程 deepseek本地部署 安裝Ollama 搜索并打開Ollama官網[Ollama](https://ollama.com/download) 點擊Download下載對應版本 下載后點擊直接安裝 安裝deepseek大語言模型 官網選擇Models 選擇deepseek-r1&#xff0c;選擇對應的模型&#xff0…

Linux - 網絡基礎(應用層,傳輸層)

一、應用層 1&#xff09;發送接收流程 1. 發送文件 write 函數發送數據到 TCP 套接字時&#xff0c;內容不一定會立即通過網絡發送出去。這是因為網絡通信涉及多個層次的緩沖和處理&#xff0c;TCP 是一個面向連接的協議&#xff0c;它需要進行一定的排隊、確認和重傳等處理…

wxWidgets GUI 跨平臺 入門學習筆記

準備 參考 https://wiki.wxwidgets.org/Microsoft_Visual_C_NuGethttps://wiki.wxwidgets.org/Tools#Rapid_Application_Development_.2F_GUI_Buildershttps://docs.wxwidgets.org/3.2/https://docs.wxwidgets.org/latest/overview_helloworld.htmlhttps://wizardforcel.gitb…

使用joblib 多線程/多進程

文章目錄 1. Joblib 并行計算的兩種模式多進程(Multiprocessing,適用于 CPU 密集型任務)多線程(Multithreading,適用于 I/O 密集型任務)2. Joblib 的基本用法3. Joblib 多進程示例(適用于 CPU 密集型任務)示例:計算平方4. Joblib 多線程示例(適用于 I/O 密集型任務)…

神旗視訊Linux client 3.4版本發布和開源

在國產化替代的大潮中&#xff0c;神旗視訊推出專為統信 Linux、麒麟 Linux OS 打造打造的開源視頻會議客戶端&#xff0c;全面適配國產 x86 及 arm64 架構 CPU&#xff0c;以穩定、安全、靈活的特性&#xff0c;為國產操作系統用戶帶來前所未有的高效溝通體驗&#xff0c;同時…

HCIA-IP路由動態-RIP

一、概念 動態路由是指路由器通過運行動態路由協議&#xff08;RIP、OSPF等&#xff09;&#xff0c;自動學習和發現網絡中的路由信息。路由器之間通過交換路由協議數據包&#xff0c;互相通告自己所知道的網絡信息&#xff0c;從而構建和更新路由表。 二、RIP(路由信息協議)…

VEC系列-RabbitMQ 入門筆記

消息隊列&#xff08;MQ&#xff09;對于開發者來說是一個經常聽到的詞匯&#xff0c;但在實際開發中&#xff0c;大多數人并不會真正用到它。網上已經有很多關于 MQ 概述和原理的詳細講解&#xff0c;官網文檔和技術博客也都介紹得很深入&#xff0c;因此&#xff0c;我在這里…

js中??是什么意思

在 JavaScript 中&#xff0c;?? 是一個邏輯運算符&#xff0c;稱為 空值合并運算符&#xff08;Nullish Coalescing Operator&#xff09;。它用于檢查左側的值是否為 null 或 undefined&#xff0c;如果是&#xff0c;則返回右側的值&#xff1b;否則返回左側的值。 語法 …

常見限流算法

限流是指在高并發、大流量請求的情況下&#xff0c;限制新的流量對系統的訪問&#xff0c;以保證系統服務的安全性。常見的限流算法及其詳細介紹如下&#xff1a; 計數器算法&#xff08;Fixed Window Counter&#xff09; 原理&#xff1a;使用一個固定時間窗口內的計數器來…

YOLOv12本地部署教程——42%速度提升,讓高效目標檢測觸手可及

YOLOv12 是“你只看一次”&#xff08;You Only Look Once, YOLO&#xff09;系列的最新版本&#xff0c;于 2025 年 2 月發布。它引入了注意力機制&#xff0c;提升了檢測精度&#xff0c;同時保持了高效的實時性能。在保持速度的同時&#xff0c;顯著提升了檢測精度。例如&am…

【原創】C# HttpClient 讀取流數據的問題

默認情況下HttpClient中有緩存&#xff0c;在讀取流數據的時候&#xff0c;往往要等一小會兒&#xff0c;然后讀出一大堆。 我們在請求OpenAI類的大模型的時候&#xff0c;往往要一邊讀取一邊顯示&#xff08;輸出&#xff09;&#xff0c;這時候需要禁止HttpClient 中內置的緩…

能源行業標桿:信創系統在智能電網中的3個創新應用案例

在當今數字化浪潮洶涌澎湃的時代&#xff0c;信息技術應用創新&#xff08;信創&#xff09;已成為推動我國經濟社會發展的重要引擎。智能電網作為能源行業的核心領域&#xff0c;其信息化建設對于保障國家能源安全和促進能源轉型具有重要意義。今天&#xff0c;讓我們一同探索…

AcWing 藍橋杯集訓·每日一題2025·5526. 平衡細菌

5526. 平衡細菌 題意 給定一個序列 ( a i ) (a_i) (ai?)&#xff0c;每次操作可以選擇一個位置 (p)&#xff0c;令從 ( a p ) (a_p) (ap?) 開始的每個數都加上一個以 (1) 或者 (-1) 為公差的從 ( 1 / ? 1 ) (1 / -1) (1/?1) 開始的等差數列。求最小化讓序列歸零的操作…

PTA 7-6 列出連通集

題目詳情&#xff1a; 給定一個有 n 個頂點和 m 條邊的無向圖&#xff0c;請用深度優先遍歷&#xff08;DFS&#xff09;和廣度優先遍歷&#xff08;BFS&#xff09;分別列出其所有的連通集。假設頂點從 0 到 n?1 編號。進行搜索時&#xff0c;假設我們總是從編號最小的頂點出…

ES中數據刷新策略refresh

在 Elasticsearch 中&#xff0c;插入數據時的 refresh 參數控制文檔在寫入后何時對搜索可見&#xff0c;其行為直接影響數據可見性和系統性能。以下是 refresh 參數的三個可選值&#xff08;true、false、wait_for&#xff09;的詳細說明及適用場景&#xff1a; 1. refreshtr…

用Python的Pandas庫解鎖數據科學:從入門到實戰

用Python的Pandas庫解鎖數據科學&#xff1a;從入門到實戰 引言 Python的Pandas庫&#xff08;名稱源自"Panel Data"&#xff09;作為數據科學生態系統的基石&#xff0c;憑借其強大的數據結構和靈活的操作功能&#xff0c;已成為全球超過90%數據工作者的首選工具。…