【Netty系列】解決TCP粘包和拆包:LengthFieldBasedFrameDecoder

目錄

如何使用?

1. 示例代碼(基于Netty)

2. 關鍵參數解釋

3. 協議格式示例

4. 常見配置場景

場景1:長度字段包含自身

場景2:長度字段在消息中間

5. 注意事項

舉個例子

完整示例:客戶端與服務端交互流程

1. 服務端代碼(含響應)

2. 客戶端代碼(含編碼器)

3. 執行流程說明

4. 網絡包結構示意圖

5. 關鍵點總結


如何使用?

以下是使用 LengthFieldBasedFrameDecoder 解決 TCP 粘包/拆包問題的 完整代碼示例關鍵解釋


1. 示例代碼(基于Netty)

// Server端代碼示例
public class NettyServer {public static void main(String[] args) {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {// 關鍵:添加 LengthFieldBasedFrameDecoderch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024,    // maxFrameLength(最大幀長度)0,       // lengthFieldOffset(長度字段偏移量)4,       // lengthFieldLength(長度字段占4字節)0,       // lengthAdjustment(長度調整值)4        // initialBytesToStrip(跳過前4字節,因為長度字段已解析)));// 將ByteBuf轉為String(按需替換為實際解碼器)ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));// 自定義業務處理器ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {System.out.println("Received message: " + msg);}});}});ChannelFuture future = bootstrap.bind(8080).sync();future.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}

2. 關鍵參數解釋

LengthFieldBasedFrameDecoder 的構造函數參數如下:

參數

說明

maxFrameLength

允許的最大幀長度(防止內存溢出)

lengthFieldOffset

長度字段的起始偏移量(通常為0)

lengthFieldLength

長度字段占用的字節數(例如4字節表示int)

lengthAdjustment

長度字段值后的內容長度調整(若長度字段包含自身長度,需調整)

initialBytesToStrip

解析后跳過的字節數(例如跳過長度字段本身)


3. 協議格式示例

假設自定義協議格式如下(長度字段在前):

+--------+----------------+
| Length |   Actual Data  |
| 4字節  |   (變長內容)    |
+--------+----------------+

4. 常見配置場景

場景1:長度字段包含自身
// 長度字段包含自身(如總長度= Length字段長度 + 數據長度)
new LengthFieldBasedFrameDecoder(1024, 0, 4, -4, 0);
// lengthAdjustment = -4(扣除長度字段自身占用的4字節)
場景2:長度字段在消息中間
// 消息格式:[Header][Length][Data]
new LengthFieldBasedFrameDecoder(1024, 2, 4, 0, 6);
// lengthFieldOffset=2(跳過Header的2字節)
// initialBytesToStrip=6(跳過Header+Length字段)

5. 注意事項

  1. 參數匹配協議:必須與協議中長度字段的位置和計算方式一致。
  2. 編解碼順序LengthFieldBasedFrameDecoder 需作為第一個解碼器添加到Pipeline。
  3. 異常處理:建議配合 ExceptionHandler 處理解碼失敗的情況。

通過這種方式,Netty 會自動根據長度字段切分完整的數據包,徹底解決粘包/拆包問題

舉個例子


完整示例:客戶端與服務端交互流程

1. 服務端代碼(含響應)
public class NettyServer {public static void main(String[] args) throws InterruptedException {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {// 添加長度字段解碼器ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));// 字符串解碼器ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));// 業務處理器(返回響應)ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {System.out.println("[Server] Received: " + msg);// 返回響應(添加長度前綴)ctx.writeAndFlush("ACK: " + msg);}});}});ChannelFuture future = bootstrap.bind(8080).sync();future.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
2. 客戶端代碼(含編碼器)
public class NettyClient {public static void main(String[] args) throws InterruptedException {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {// 添加編碼器(為消息添加長度前綴)ch.pipeline().addLast(new MessageToByteEncoder<String>() {@Overrideprotected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) {byte[] bytes = msg.getBytes(CharsetUtil.UTF_8);out.writeInt(bytes.length); // 寫入4字節長度字段out.writeBytes(bytes);      // 寫入實際數據}});// 響應解碼器(與服務端解碼器對稱)ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));// 業務處理器(打印響應)ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {System.out.println("[Client] Received: " + msg);}});}});ChannelFuture future = bootstrap.connect("localhost", 8080).sync();// 發送兩條測試消息(自動處理粘包)future.channel().writeAndFlush("Hello Netty");future.channel().writeAndFlush("Test Message");future.channel().closeFuture().sync();} finally {group.shutdownGracefully();}}
}

3. 執行流程說明

  1. 客戶端發送消息
    • 編碼器將字符串轉換為 長度字段(4字節) + 實際數據 的二進制格式。
    • 示例消息 "Hello Netty" 的傳輸格式:
+----------+-----------------+
| 0x00000B | "Hello Netty"   |  // 0x00000B = 11字節(字符串長度)
+----------+-----------------+
  1. 服務端解析消息
    • LengthFieldBasedFrameDecoder 根據長度字段切分完整數據包。
    • StringDecoder 將二進制數據轉為字符串,業務處理器打印并返回響應。
  1. 客戶端接收響應
    • 服務端返回的 "ACK: Hello Netty" 同樣通過長度字段編碼。
    • 客戶端解碼器解析后打印響應信息。

4. 網絡包結構示意圖

客戶端發送:
[Length=11][Data="Hello Netty"][Length=12][Data="Test Message"]服務端接收:
[Length=11][Data="Hello Netty"] → 完整解析為獨立消息
[Length=12][Data="Test Message"] → 完整解析為獨立消息服務端響應:
[Length=16][Data="ACK: Hello Netty"]
[Length=17][Data="ACK: Test Message"]

5. 關鍵點總結

  • 編碼對稱性:客戶端和服務端的編解碼器需匹配(長度字段位置一致)。
  • 自動分包LengthFieldBasedFrameDecoder 自動處理TCP流中的粘包/拆包。
  • 性能保障:基于長度字段的解析效率極高,適合高頻數據傳輸場景。

運行示例后,你將在控制臺看到完整的請求-響應日志,驗證粘包問題的解決效果。

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

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

相關文章

哈爾濱工業大學提出ADSUNet—紅外暗弱小目標鄰幀檢測新框架

ADSUNet: Accumulation-Difference-Based Siamese U-Net for inter-frame Infrared Dim and Small Target Detection 作者單位&#xff1a;哈爾濱工業大學空間光學工程研究中心 引用: Liuwei Zhang, Yuyang Xi, Zhipeng Wang, Wang Zhang, Fanjiao Tan, Qingyu Hou, ADSUNet: A…

Linux開發追蹤(IMX6ULL篇_第一部分)

前言 參數&#xff1a;cortex-A7 698Mhz flash 8GB RAM 512M DDR3 2個100M網口 單核 初期&#xff1a; 一、安裝完虛擬機之后&#xff0c;第一步先設置文件之間可以相互拷貝復制&#xff0c;以及通過CRT連接到虛擬機等 折磨死人了啊啊啊啊啊啊 1、關于SSH怎么安裝…

【萌筆趣棋】網頁五子棋項目測試報告

目錄 一.項目介紹 &#xff08;一&#xff09;項目簡介 &#xff08;二&#xff09;功能介紹 &#xff08;三&#xff09;頁面展示 1.注冊頁面 2.登錄頁面 3.游戲大廳頁面 4.游戲房間頁面&#xff08;對戰&#xff09; 二.功能測試 &#xff08;一&#xff09;出現的…

知識圖譜增強的大型語言模型編輯

https://arxiv.org/pdf/2402.13593 摘要 大型語言模型&#xff08;LLM&#xff09;是推進自然語言處理&#xff08;NLP&#xff09;任務的關鍵&#xff0c;但其效率受到不準確和過時知識的阻礙。模型編輯是解決這些挑戰的一個有前途的解決方案。然而&#xff0c;現有的編輯方法…

數據庫,Spring Boot,數據源

您是對的&#xff0c;我之前的回答解釋了Spring Boot在操作MySQL時不一定需要顯式配置指定的數據源類型&#xff0c;因為它有自動配置機制&#xff0c;但沒有直接點明在自動配置情況下“數據源是什么”。 在Spring Boot自動配置機制下&#xff0c;這個“數據源”指的是一個連接…

數據結構測試模擬題(3)

1、兩個有序鏈表序列的合并 #include<bits/stdc.h> using namespace std;struct node{int num;node* next; };// 創建鏈表 node* CreatList(){int x;node *head new node(); // 創建頭節點head->next NULL;node *tail head; // 尾指針初始指向頭節點while…

LabVIEW Val (Sgnl) 屬性

在 LabVIEW 事件驅動架構中&#xff0c;Val (Sgnl) 屬性&#xff08;Value (Signaling)&#xff09;是實現編程觸發與用戶交互行為一致性的關鍵技術。與普通 Value 屬性不同&#xff0c;Val (Sgnl) 在修改控件值的同時強制生成值改變事件&#xff0c;確保程序邏輯與 UI 交互保持…

04.MySQL數據類型詳解

MySQL數據類型詳解 文章目錄 MySQL數據類型數據類型分類數值類型 tinyint類型bit類型float類型decimal類型 字符串類型 char類型varchar類型char和varchar比較 時間日期類型enum和set類型數據類型選擇的進階技巧常見誤區與解決方案性能優化與最佳實踐 MySQL數據類型 數據類型…

Spring AI 之對話記憶(Chat Memory)

大型語言模型&#xff08;LLMs&#xff09;是無狀態的&#xff0c;這意味著它們不會保留關于之前交互的信息。當想在多次交互中保持上下文或狀態時&#xff0c;這可能會成為一個限制。為了解決這一問題&#xff0c;Spring AI 提供了對話記憶功能&#xff0c;允許你在與大型語言…

H?lder Statistical Pseudo Divergence Proper H?lder Divergence

目錄 Hlder Statistical Pseudo DivergenceProper Hlder Divergence Hlder Statistical Pseudo Divergence Hlder Statistical Pseudo Divergence是一種度量兩個概率分布 p p p 和 q q q差異的方法&#xff0c;它基于Hlder不等式。定義如下&#xff1a; D α H ( p : q ) 1 …

時序數據庫IoTDB基于云原生的創新與實踐

概述 Apache IoTDB 是一款獨立自研的物聯網時序數據庫&#xff0c;作為 Apache 基金會的頂級項目&#xff0c;它融合了產學研的優勢&#xff0c;擁有深厚的科研基底。IoTDB 采用了端邊云協同的架構&#xff0c;專為物聯網設計&#xff0c;致力于提供極致的性能。 數據模型 I…

git 如何解決分支合并沖突(VS code可視化解決+gitLab網頁解決)

1、定義&#xff1a;兩個分支修改了同一文件的同一行代碼&#xff0c;無法自動決定如何合并代碼&#xff0c;需要人工干預的情況。&#xff08;假設A提交了文件a,此時B在未拉取代碼的情況下&#xff0c;直接提交是會報錯的&#xff0c;此時需要拉取之后再提交才會成功&#xff…

系統架構設計師(一):計算機系統基礎知識

系統架構設計師&#xff08;一&#xff09;&#xff1a;計算機系統基礎知識 引言計算機系統概述計算機硬件處理器處理器指令集常見處理器 存儲器總線總線性能指標總線分類按照總線在計算機中所處的位置劃分按照連接方式分類按照功能分類 接口接口分類 計算機軟件文件系統文件類…

聊一聊接口測試中緩存處理策略

目錄 一、強制繞過緩存 添加時間戳參數 修改請求頭 二、主動清除緩存 清除本地緩存 清除服務端緩存&#xff08;需權限&#xff09; 清除CDN緩存 三、測試緩存邏輯 首次請求獲取數據 記錄響應頭中的緩存標識????? 驗證緩存生效 測試緩存過期??????? 四…

機器學習算法-邏輯回歸

今天我們用 「預測考試是否及格」 的例子來講解邏輯回歸&#xff0c;從原理到實現一步步拆解&#xff0c;保證零基礎也能懂&#xff01; &#x1f3af; 例子背景 假設你是班主任&#xff0c;要根據學生的「學習時間」預測「是否及格」&#xff0c;手上有以下數據&#xff1a;…

【論文解讀】CVPR2023 PoseFormerV2:3D人體姿態估計(附論文地址)

論文鏈接&#xff1a;https://arxiv.org/pdf/2303.17472 源碼鏈接&#xff1a;https://github.com/QitaoZhao/PoseFormerV2 Abstract 本文提出了 PoseFormerV2&#xff0c;通過探索頻率域來提高 3D 人體姿態估計的效率和魯棒性。PoseFormerV2 利用離散余弦變換&#xff08;DC…

DRW - 加密市場預測

1.數據集描述 在本次比賽中&#xff0c;數據集包含加密市場的分鐘級歷史數據。您的挑戰是預測未來的加密貨幣市場價格走勢。這是一項kaggle社區預測競賽&#xff0c;您可以以 CSV 文件的形式或通過 Kaggle Notebooks 提交您的預測。有關使用 Kaggle Notebooks 的更多詳細信息&a…

嵌入式Linux系統中的啟動分區架構

在嵌入式Linux系統架構中,Linux內核、設備樹(Device Tree)與引導配置文件構成了系統啟動的基礎核心。如何安全、高效地管理這些關鍵文件,直接影響到系統的穩定性與可維護性。近年來,越來越多的嵌入式Linux開發者選擇將啟動相關文件從傳統的“混合存放”方式,轉向采用獨立…

用戶資產化視角下開源AI智能名片鏈動2+1模式S2B2C商城小程序的應用研究

摘要&#xff1a;在數字化時代&#xff0c;平臺流量用戶尚未完全轉化為企業的數字資產&#xff0c;唯有將其沉淀至私域流量池并實現可控、隨時觸達&#xff0c;方能成為企業重要的數字資產。本文從用戶資產化視角出發&#xff0c;探討開源AI智能名片鏈動21模式S2B2C商城小程序在…

Spring是如何實現屬性占位符解析

Spring屬性占位符解析 核心實現思路1?? 定義占位符處理器類2?? 處理 BeanDefinition 中的屬性3?? 替換具體的占位符4?? 加載配置文件5?? Getter / Setter 方法 源碼見&#xff1a;mini-spring 在使用 Spring 框架開發過程中&#xff0c;為了實現配置的靈活性&#xf…