Netty編解碼器

目錄

1、概念

2、Netty提供的編解碼器類型

2.1 解碼器

2.1.1?ByteToMessageDecoder

2.1.2?ReplayingDecoder

2.1.3?MessageToMessageDecoder

2.2 編碼器

2.2.1?MessageToByteEncoder

2.2.2?MessageToMessageEncoder

2.3 編解碼器

2.3.1?ByteToMessageCodec

2.3.2?MessageToMessageCodec

2.3.3?CombinedChannelDuplexHandler

3、使用注意事項

4、示例:一個簡單的字符串編解碼器


1、概念

Netty 的編解碼器是其網絡編程框架中的核心組件,負責處理網絡通信中最基本也最關鍵的字節與消息對象之間的相互轉換

核心概念:

  • 解碼器:?將接收到的原始字節流?(ByteBuf) 轉換成有意義的應用程序級消息對象。這個過程發生在數據入站時(從網絡到應用)。

  • 編碼器:?將應用程序級的消息對象轉換成字節流?(ByteBuf),以便通過網絡發送。這個過程發生在數據出站時(從應用到網絡)。

  • 編解碼器:?同時實現了編碼器和解碼器功能的組件。

解決的問題:

  • 解碼:?解決如何從連續的、可能被 TCP 粘包/拆包的字節流中,正確地切割、識別并還原出發送方發送的一個個完整消息。

  • 編碼:?解決如何將結構化的消息對象高效地、符合協議規范地序列化成字節序列,以便發送。

2、Netty提供的編解碼器類型

2.1 解碼器

Netty 的解碼器都實現了?ChannelInboundHandler?接口,處理入站數據。需要將解碼器放在ChannelPipeline中。常見的抽象基類和實現:

2.1.1?ByteToMessageDecoder

  • 功能:?將入站的?ByteBuf?累積到內部的緩沖區中,直到有足夠的數據可以解碼成一個完整的消息對象。需要檢查緩沖區是否有足夠的字節。

  • 關鍵方法:?decode(ChannelHandlerContext ctx, ByteBuf in, List out)

    • in: 當前累積的、可讀的輸入?ByteBuf

    • out: 用于存放解碼成功的完整消息對象的列表。每添加一個對象,就表示成功解碼了一條消息。

  • 職責:?開發者繼承此類,實現?decode?方法:

    1. 檢查?in?中是否有足夠的數據構成一個完整消息。

    2. 如果足夠,從?in?中讀取數據,構造出消息對象。

    3. 將構造好的消息對象添加到?out?列表中。

    4. 重復步驟 1-3 直到?in?中不再有足夠的數據構成完整消息。

  • 內部緩沖:?它會自動管理累積的字節,處理粘包問題。當?in?被讀取后,已讀取的字節會被丟棄,保留未讀取的字節供下次解碼。

  • 示例:?LineBasedFrameDecoder?(基于換行符拆包),?FixedLengthFrameDecoder?(固定長度拆包),?LengthFieldBasedFrameDecoder?(基于長度字段拆包 -?極其重要和常用)。

2.1.2?ReplayingDecoder

  • 特點:?簡化了解碼邏輯。它假設在調用?decode?方法時,ByteBuf?in?中總是有足夠的數據可供讀取下一個需要的字段。如果數據不足,它會拋出特殊異常(由框架捕獲),并等待更多數據到來后重試解碼。

  • 優點:?代碼更簡潔,不需要手動檢查每個字段是否有足夠數據。

  • 缺點:?性能可能略低于?ByteToMessageDecoder?(因為需要異常機制),且?in?的某些操作受限(如?readableBytes()),不是所有的ByteBuff都支持。

  • 適用:?協議簡單或對極致性能要求不苛刻的場景。

2.1.3?MessageToMessageDecoder

  • 核心:?將一種消息對象解碼成另一種消息對象

  • 功能:?用于消息處理管道中的消息轉換階段。輸入和輸出都是對象,不再是原始的?ByteBuf

  • 關鍵方法:?decode(ChannelHandlerContext ctx, I msg, List out)

    • msg: 輸入的上一個 Handler 傳遞下來的消息對象(類型?I)。

    • out: 存放轉換后的消息對象(類型?O)的列表。

  • 示例:?將?ByteBuf?解碼成的?String?對象再解碼成自定義的?LoginRequest?對象;將 Protobuf 的?ByteBuf?解碼成生成的?MessageLite?對象。

2.2 編碼器

Netty 的編碼器都實現了?ChannelOutboundHandler?接口,處理出站數據。常見的抽象基類和實現:

2.2.1?MessageToByteEncoder

  • 功能:?將應用程序的消息對象編碼成字節流?(ByteBuf)。

  • 關鍵方法:?encode(ChannelHandlerContext ctx, I msg, ByteBuf out)

    • msg: 要編碼的消息對象(類型?I)。

    • out: 用于寫入編碼后字節的目標?ByteBuf

  • 職責:?開發者繼承此類,實現?encode?方法:

    1. 將?msg?對象包含的信息(如字段值)按照協議規范寫入到?out?ByteBuf?中。

    2. 通常需要處理長度字段(如果需要)、序列化等。

  • 示例:?將?String?編碼成?ByteBuf?(通常使用?ctx.alloc().buffer()?創建并寫入字節),將自定義的?LoginResponse?對象編碼成協議規定的字節格式。

2.2.2?MessageToMessageEncoder

  • 核心:?將一種消息對象編碼成另一種消息對象

  • 功能:?用于消息處理管道中的消息轉換階段,輸出對象通常最終會被下游的?MessageToByteEncoder?處理。

  • 關鍵方法:?encode(ChannelHandlerContext ctx, I msg, List out)

    • msg: 要轉換的消息對象(類型?I)。

    • out: 存放轉換后的消息對象(類型?O)的列表。

  • 示例:?將自定義的?LoginResponse?對象轉換成 Protobuf 生成的?MessageLite?對象;將?String?轉換成包含該字符串的?TextWebSocketFrame

2.3 編解碼器

編碼解碼器: 同時具有編碼與解碼功能,特點同時實現了ChannelInboundHandler和ChannelOutboundHandler接口,因此在數據輸入和輸出時都能進行處理。Netty提供提供了一個ChannelDuplexHandler適配器類,編碼解碼器的抽象基類。

2.3.1?ByteToMessageCodec

結合了?ByteToMessageDecoder?和?MessageToByteEncoder

2.3.2?MessageToMessageCodec

結合了?MessageToMessageDecoder?和?MessageToMessageEncoder

2.3.3?CombinedChannelDuplexHandler

一個更靈活的通用組合方式,允許你將任意一個解碼器 (ChannelInboundHandler) 和任意一個編碼器 (ChannelOutboundHandler) 組合在一起,作為一個編解碼器添加到 pipeline 中。這是推薦的方式來組合獨立的編解碼邏輯,避免多重繼承可能帶來的問題。

public class MyCodec extends CombinedChannelDuplexHandler<MyDecoder, MyEncoder> {public MyCodec() {super(new MyDecoder(), new MyEncoder());}
}

3、使用注意事項

  • 處理 TCP 粘包/拆包:?這是解碼器的核心職責之一。務必使用?ByteToMessageDecoder?或其子類(如?LengthFieldBasedFrameDecoder)來自動累積和拆包。不要試圖在?channelRead?中直接處理原始?ByteBuf?來解析完整消息

  • 使用 LengthFieldBasedFrameDecoder:?對于自定義二進制協議,這是最常用、最可靠的拆包解碼器。它通過協議頭中明確指定的長度字段來確定一個完整幀的邊界,完美解決粘包拆包問題。

  • 資源管理:?ByteBuf?是 Netty 管理的內存。在編碼器?encode?方法中創建的?ByteBuf,Netty 框架會在寫入完成后負責釋放。在解碼器?decode?方法中,不要釋放傳入的?ByteBuf?inByteToMessageDecoder?會自動管理其生命周期。處理?out?列表中的對象時,確保它們被正確傳遞下去或被釋放(如果需要)。遵循 Netty 的引用計數規則。

  • 可重用性:?編解碼器通常是線程安全的和無狀態的,可以被多個 Channel 共享(添加時使用?@Sharable?注解并確保確實無狀態)。

  • Pipeline 順序:

    • 解碼器 (ChannelInboundHandler) 應該添加在靠近?SocketChannel?的一端(Pipeline 的前端)。

    • 編碼器 (ChannelOutboundHandler) 應該添加在靠近業務邏輯 Handler 的一端(Pipeline 的后端)。

    • 一個典型的 Pipeline 順序可能是:LengthFieldBasedFrameDecoder?->?MyProtocolDecoder?(ByteToMessageDecoder) ->?MyBusinessLogicHandler?->?MyProtocolEncoder?(MessageToByteEncoder) ->?...?(其他出站處理器如日志、加密)。

  • 利用現有實現:?優先使用 Netty 內置的編解碼器(如 HTTP、WebSocket、Protobuf、Marshalling、Base64 等),它們經過充分測試和優化。

  • 性能:?編解碼通常是性能關鍵路徑。避免在編解碼方法中進行阻塞操作或創建過多臨時對象。考慮使用對象池(如 Recycler)復用消息對象。

4、示例:一個簡單的字符串編解碼器

// 編碼器 (出站:Object -> ByteBuf)
@Sharable
public class StringEncoder extends MessageToByteEncoder<String> {@Overrideprotected void encode(ChannelHandlerContext ctx, String msg, ByteBuf out) throws Exception {// 將字符串寫入ByteBuf (使用UTF-8編碼)out.writeCharSequence(msg, StandardCharsets.UTF_8);}
}// 解碼器 (入站:ByteBuf -> String)
@Sharable
public class StringDecoder extends ByteToMessageDecoder {@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {// 簡單示例:假設每個ByteBuf都包含一個完整的UTF-8字符串// 實際中需要處理粘包拆包!這里僅作演示。out.add(in.toString(StandardCharsets.UTF_8));in.readerIndex(in.writerIndex()); // 標記所有字節已讀 (僅用于此簡單示例)}
}// 或者使用更健壯的 LineBasedFrameDecoder + StringDecoder 組合來處理行分隔的消息
public class ServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline();// 入站 Pipeline (從網絡到應用)p.addLast(new LineBasedFrameDecoder(1024)); // 按行拆包,最大行長度1024p.addLast(new StringDecoder(StandardCharsets.UTF_8)); // 將一行字節轉成Stringp.addLast(new MyStringHandler()); // 業務邏輯處理器,處理String對象// 出站 Pipeline (從應用到網絡)p.addLast(new StringEncoder(StandardCharsets.UTF_8)); // 將String轉成字節}
}

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

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

相關文章

企業內部安全組網技術解析:安全通道選型、零信任架構與數據合規加密防護

一、引言&#xff1a;企業內部安全組網的重要性 隨著企業數字化轉型的深入以及遠程辦公需求的增加&#xff0c;企業內部異地組網逐漸成為企業信息技術部門關注的重要話題。如何在合規合法的前提下&#xff0c;保障企業內部網絡連接的安全性、穩定性&#xff0c;并有效保護企業…

Windows 4625日志類別解析:未成功的賬戶登錄事件

Windows 4625日志類別解析&#xff1a;未成功的賬戶登錄事件 什么是Windows 4625日志&#xff1f; Windows 4625日志屬于安全日志&#xff08;Security Log&#xff09; 的一部分&#xff0c;記錄系統中未成功的賬戶登錄嘗試&#xff08;Failed Logon&#xff09;。它是追蹤非…

3D看房實現房屋的切換

作為3D看房的補充&#xff0c;在這里&#xff0c;我們講一下如何實現房屋的切換&#xff0c;我這里提供兩種思路&#xff0c; 切換貼圖&#xff0c;切換場景&#xff0c; 接下我們按照較復雜的場景切換來講&#xff0c;切換貼圖也就水到渠成&#xff1a; 初始化場景&#xf…

[Android]ANR的線程

ANR的原理是進行了超時告警&#xff0c;在執行一個需要被監控的任務時&#xff0c;注冊一個超時提醒&#xff0c;如果很快執行好了&#xff0c;刪除這個提醒&#xff0c;如果超時&#xff0c;這個提醒就被觸發&#xff0c;這個超時處理是通過handler方式來調用的&#xff0c;這…

RLVR來做Agent任務能力增強訓練

和上一篇其實有點承接 上一篇的爭論其實是因為要優化agent的任務規劃和實現能力的 所以有了self-learning之爭 當我們說Self-learning&#xff0c;其實是在說什么&#xff1f; 其實上一篇最后時候提了一點拿RLVR來做agent的任務提升 正好今天看到了一篇應景的論文&#xf…

如何運營一個開源項目并取得較大影響力?

開源不僅是主要的軟件開發方法論&#xff0c;還是助力快速創新、分散協作、 生態系統建設和職業發展的卓越戰略。如今&#xff0c;無論在哪里&#xff0c;都離不開與 開源的互動。開源存在于你的手機、汽車和冰箱中&#xff0c;它使你最喜歡的節 目或電影的制作和發行成為可能&…

華為高斯數據庫的數據類型

華為高斯數據庫的數據類型 國產數據庫華為高斯的GaussDB的數據類型 華為高斯數據庫的數據類型? 一、數值類型&#xff08;Numeric Types&#xff09;? 二、字符類型&#xff08;Character Types&#xff09;? 三、布爾類型&#xff08;Boolean Type&#xff09;? 四、日期和…

生物實驗室安全、化學品安全

zhihu.com/column/c_1922752541369800632 Docs 目錄 第七章 7.1 實驗室生物安全等級 7.1.1 生物安全基本概念 7.1.2 生物的危害等級 7.1.2.1 國內生物危害等級 7.1.3 實驗室生物安全防護水平分級 7.2 實驗室生物安全控制 7.2.1 實驗室生物儀器設備安全控制 7.2.1.1 生…

【QT】第一個QT程序 || 對象樹 || 編碼時的注意事項

一、編寫第一個 Qt 程序 1. 開發環境搭建 安裝 Qt Creator&#xff08;推薦使用官方在線安裝器&#xff09;安裝 Qt 庫&#xff08;如 Qt 5.15.2 或 Qt 6.x&#xff09;配置編譯器&#xff08;MinGW / MSVC / GCC&#xff09; 2. 創建一個簡單的 Qt GUI 應用程序 打開 Qt C…

多服務器IP白名單配置(使用redis stream實現)

應用背景 現在我有一個管理平臺,可以通過代理連接到內網網站,但是這個代理服務器沒有設置密碼,所以需要IP白名單讓指定用戶才可以使用代理。 添加白名單流程圖 流程描述: 登錄管理平臺成功后,管理平臺的后臺將這個登錄的IP地址添加到redis,并設置過期時間為24小時redis…

Vue 3 Teleport 特性

目錄 基本用法? 搭配組件使用? 禁用 Teleport? 多個 Teleport 共享目標? 延遲解析的 Teleport ? 總結 <Teleport> 是一個內置組件&#xff0c;它可以將一個組件內部的一部分模板“傳送”到該組件的 DOM 結構外層的位置去。 基本用法? 有時我們可能會遇到這…

常用指令合集(DOS/Linux/git/Maven等)

文章目錄 常用指令收集vmware 虛擬機聯網設置ubuntu 常見問題設置apt 相關指令&#xff1a;gcc 編譯相關指令 sqlite3VSCode 快捷鍵&#xff1a;收索引擎技巧&#xff08;google&#xff09;Intelideashell--LinxvimgitDOS:mavendockerkubectl 指令nginx配置redis-clientMySQLl…

ABP VNext + MassTransit:構建分布式事務與異步消息協作

ABP VNext MassTransit&#xff1a;構建分布式事務與異步消息協作 &#x1f680; &#x1f4da; 目錄 ABP VNext MassTransit&#xff1a;構建分布式事務與異步消息協作 &#x1f680;&#x1f4da; 1. 背景與動機&#x1f6e0;? 2. 環境與依賴&#x1f527; 3. 在 ABP 模塊…

語義網技術

用通俗語言說語義網技術&#xff0c;以及它和現在互聯網的關系 一、語義網技術&#xff1a;讓網絡“聽懂人話”的智能升級 現有互聯網就像一本巨大的“圖文報紙”&#xff1a;我們人類看文章、圖片能輕松理解意思&#xff0c;但計算機只能識別文字符號&#xff0c;不知道“蘋…

pytorch學習—4.反向傳播(用pytorch算梯度)

2. 線性模型 3.梯度下降算法 4.反向傳播_嗶哩嗶哩_bilibili 4.1 代碼復現 import torch import matplotlib.pyplot as pltx_data=[1.0,2.0,3.0] y_data=[2.0,4.0,6.0]#這里創建了一個PyTorch張量w,初始值為1.0,并且設置requires_grad=True, #這意味著在計算過程中,PyTo…

7類茶葉嫩芽圖像分類數據集

在茶葉育種、溯源管理與自動采摘等智能農業場景中&#xff0c;茶樹品種的識別與分類是一項關鍵任務。不同茶葉品種在嫩芽期表現出顯著的形態差異&#xff0c;例如顏色、葉緣結構、芽頭密度等。因此&#xff0c;基于圖像的茶葉品種分類不僅具備實際應用價值&#xff0c;也為農業…

【Elasticsearch】Linux環境下安裝Elasticsearch

一&#xff0c;前言 Elasticsearch&#xff08;簡稱 ES&#xff09;是一個基于 ??Apache Lucene?? 構建的開源分布式搜索與分析引擎。它支持??實時數據處理??&#xff0c;提供近實時的全文搜索能力&#xff0c;并通過 ??JSON 格式的 RESTful API?? 實現數據索引與檢…

【數據結構--樹于哨兵查找-1】

查找 從前到后- 線性查找 -就是順序查找. 哨兵法查找–節省每次都要判斷是否越界的這一步驟利于節省開銷&#xff0c;從而提升效率。 參考我的程序 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <stdbool.h>#define SIZE …

MyBatis修改(update)操作

1. 三步法口訣 “接口收對象&#xff0c;SQL全賦值&#xff0c;主鍵定目標” 2. 詳細記憶點 | 步驟 | 口訣 | 說明與示例 | |--------------|----------------|----------------------------------------------------------------------------| | 1. 寫接口 | “接口收對象…

Spring Boot 入門學習

一、 Web應用開發概述 什么是Web應用 1. Web應用 &#xff08;Web Application&#xff09;是一種運行在Web服務器上的軟件程序&#xff0c;由用戶通過Web瀏覽器進行訪問和交互。 2.Web應用與傳統的桌面應用不同&#xff0c;它不需要在個人計算機上安裝特定的軟件&#xff0…