Netty(三):網路傳輸中的拆包、粘包問題
問題來源:
在Netty中對於TCP傳輸的預設資料大小為1024位元組,當資料包不超過1024時,會一次接收完畢,當超過1024時,首先會進行拆分,即分成幾次傳輸,等到下次連線時將會改變一次發包的資料大小為2048位元組,然後下次增長為3072位元組,然後下次增長為4096位元組;然而,再往下增長,則增長了2048位元組變為6144位元組,然後變為8192位元組(8KB),當資料再大時,接收到的資料包也不再改變。此後,只要傳送的資料包大小不超過8192位元組,便不再分包。
當一次連線的資料被分成幾次進行傳輸時就帶來一個問題:channelPipeline會把資料儲存起來,然後每一次收到服務端發回來的資料時,將會觸發一次channelRead方法,然後就會對收到的資料進行解析(因為此刻認為資料已經傳輸完畢,然而實際並沒有),那麼因為是拆分的資料所以就會導致解析失敗!
解決方案:
在初始化bootstrap(啟動器)時,要進行handler的註冊,handler是以責任鏈的設計模式設計的,即channel讀取時按照頭handler——尾handler的流程,channel寫入時按照尾handler——頭handler的流程。所以我們必須在觸發channelRead方法前先對資料進行處理,所以提出以下解決方案:在處理資料的handler之前註冊一個decode的handler來保證接受到的資料的完整性。
這裡的decode方法繼承自ByteToMessageDecoder類。因為專案開發基於騰訊的Tars框架,從Tars框架原始碼(https://github.com/Tencent/Tars)中我們可以看到:
public static IoBuffer encodeResponse(TarsServantResponse response, String charsetName) throws ProtocolException {
……
……
ByteBuffer buffer = jos.getByteBuffer();
int datalen = buffer.position();
buffer.position(0);
buffer.putInt(datalen);
buffer.position(datalen);
return IoBuffer.wrap(jos.toByteArray());
}
在encodeResponse方法中,最後將整個資料長度放入了緩衝區的開頭。那麼我們在decode的時候就可以先讀取資料的長度,然後限制資料的讀入長度,得到完整的資料後再進行處理。處理框圖如下:
具體程式碼如下:
public class CommunicateDecoder extends ByteToMessageDecoder {
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
int length = in.getInt(0);
// Logs.access.info(">>>>>>>>> length is : {}", length);
if(in.readableBytes() >= length) {
// Logs.access.info(">>>>>>>>> in is : {}", in);
ByteBuf unPool = Unpooled.buffer(length);
in.readBytes(unPool, length);
// Logs.access.info(">>>>>>>>> in after read is : {}", in);
// Logs.access.info(">>>>>>>>> unPool is : {}", unPool);
out.add(unPool); // unPool
// Logs.access.info(">>>>>>>>> ready to send!");
}
}
}
相關推薦
Netty(三):網路傳輸中的拆包、粘包問題
問題來源: 在Netty中對於TCP傳輸的預設資料大小為1024位元組,當資料包不超過1024時,會一次接收完畢,當超過1024時,首先會進行拆分,即分成幾次傳輸,等到下次連線時將會改變一次
Python併發程式設計(三):網路程式設計之粘包現象
目錄 一、什麼是粘包 須知:只有TCP有粘包現象,UDP永遠不會粘包 粘包不一定會發生 如果發生了:1.可能是在客戶端已經粘了 2.客戶端沒有粘,可能是在服務端粘了 首先需要掌握一個socket收發訊息的原理 應用
EOS學習(三):在nodeos中管理錢包
通過keosd、cleos管理錢包,可參見 EOS學習(一):賬戶與錢包使用nodeos管理錢包,並非是優選配置模式,但該模式適用於開發和測試中使用。這裡並不推薦同時使用keosd和nodeos進行錢包管理,這樣做雖然不會破壞任何規則,但會讓我們的使用過程非常困惑。為了使用n
Docker(三):Docker映象匯入與匯出、恢復與載入與在Docker容器中安裝軟體
一、映象的匯入與匯出:import 與export 命令通常用於Docker映象的匯入匯出。1、將映象匯出到檔案:(1)命令格式:docker export 已經存在的映象id或者映象名稱 >
列舉類(三):列舉類中幾個常用的方法
列舉類中的幾個常見方法 int compareTo(E o) String name() int ordinal() String toString() <T> T valueOf(Class<T> type,String name) values(
矩陣論(三):矩陣分解—從Schur分解、特徵值分解EVD到奇異值分解SVD
本篇部落格針對三種聯絡十分緊密的矩陣分解(Schur分解、特徵值分解、奇異值分解)依次介紹,它們的關係是Schur→EVD→SVDSchur\rightarrow{}EVD\rightarrow{}SVDSchur→EVD→SVD,也就是說由Schur分解可以推
Android-json解析(三):原生JSONObject+JSONArray的解析、遍歷及生成等
一、JSONObject和JSONArray的資料表示形式 JSONObject的資料是用 { } 來表示的, 例如: { "id":"1", "courseID":"化學", "title":"滴定實驗",
縮放系列(三):一個可以手勢縮放、拖拽、旋轉的layout
弄了一個下午,終於搞出來了,PowerfulLayout 下面是一個功能強大的改造的例子: 可以實現以下需求: 1.兩個手指進行縮放佈局 2.所有子控制元件也隨著縮放, 3.子控制元件該有的功能不能丟失(像button有可被點選的功能,縮放後不能丟失該功能)
網易雲信即時通訊推送保障及網路優化詳解(三):如何在弱網環境下優化大資料傳輸
對於移動 APP 來說,IM 功能正變得越來越重要,它能夠建立起人與人之間的連線。社交類產品中,使用者與使用者之間的溝通可以產生出更好的使用者粘性。在複雜的 Android 生態環境下,多種因素都會造成訊息推送不能及時達到客戶端。另外,不穩定的行動網路也給資料傳輸的速率和可靠
SQL Server 2005中的分區表(三):將普通表轉換成分區表
成了 insert 刪掉 -- pri light part ide 新建 在設計數據庫時,經常沒有考慮到表分區的問題,往往在數據表承重的負擔越來越重時,才會考慮到分區方式,這時,就涉及到如何將普通表轉換成分區表的問題了。 那麽,如何將一個普通表轉換成一個分區表 呢
Java中String、StringBuilder、StringBuffer常用源碼分析及比較(三):String、StringBuilder、StringBuffer比較
val str 成員變量 相同 += let .get end art 看這篇隨筆之前請務必先看前面兩章: Java中String、StringBuilder、StringBuffer常用源碼分析及比較(一):String源碼分析 Java中String、StringBui
在 Windows Server Container 中運行 Azure Storage Emulator(三):運行在容器中
們的 x86 有關 doc fault ps1 count1 ora isn 上一節中,我們已經準備好了 SQL Server,那麽接下來,我們要把 ASE 放到容器裏了。 首先,新建 Start.ps1,內容如下: 1 param( 2 [Param
Zookeeper詳解(三):Zookeeper中的Znode特性
zookeeper數據模型 znode 節點數據 數據模型ZK擁有一個命名空間就像一個精簡的文件系統,不同的是它的命名空間中的每個節點擁有它自己或者它下面子節點相關聯的數據。ZK中必須使用絕對路徑也就是使用“/”開頭。Znode:ZK目錄樹中每個節點對應一個Znode。每個Znode維護這一個屬性
由散列表到BitMap的概念與應用(三):面試中的海量資料處理
一道面試題 在面試軟體開發工程師時,經常會遇到海量資料排序和去重的面試題,特別是大資料崗位。 例1:給定a、b兩個檔案,各存放50億個url,每個url各佔64位元組,記憶體限制是4G,找出a、b檔案共同的url? 首先我們最常想到的方法是讀取檔案a,建立雜湊表,然後再讀取檔案b,遍歷檔
安卓專案實戰之強大的網路請求框架okGo使用詳解(三):快取的使用
相關實體類必須實現序列化介面 使用快取前,必須讓涉及到快取javaBean物件實現Serializable介面,否者會報NotSerializableException。因為快取的原理是將物件序列化後直接寫入資料庫中,如果不實現Serializable介面,會導致物件無法序列化,進而無法
基於中臺思想的物流系統設計(三):構建物流地址能力
一、引言 在電商物流領域我們會涉及到地址,其中包括了基礎的四級地址和使用者填寫的地址。四級地址在整個從下單到收貨的業務流程中都會用到,因此設計的時候要考慮如何最大限度地提高QPS。使用者地址在下單的時候讓使用者填寫或者選擇,然後存在交易訂單和物流訂單上,後續的流程一般不會變,如果使用者需要修改地址,直接變
Spring Boot中使用WebSocket總結(三):使用訊息佇列實現分散式WebSocket
在上一篇文章(www.zifangsky.cn/1359.html)中我介紹了服務端如何給指定使用者的客戶端傳送訊息,並如何處理對方不線上的情況。在這篇文章中我們繼續思考另外一個重要的問題,那就是:如果我們的專案是分散式環境,登入的使用者被Nginx的反向代理分配到多個不同伺服器,那麼在其中一個伺服器建立了W
Docker系列(三):將.net core api部署到Kubernetes (K8s)中
1.新建一個WebApi專案,並新增Dockerfile檔案: FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base WORKDIR /app EXPOSE 80 FROM microsoft/dotnet:2.1-sdk AS build WOR
Windows網路程式設計(三):建立TCP連線和收發訊息
先看服務端: // ConsoleApplication3.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #define _WINSOCK_DEPRECATED_NO_WARNINGS //這個宣告要在stdafx.h的後面,但要
神經網路(三):神經網路
一、 神經元到神經網路 在之前的文章中(《神經網路(一)》和《神經網路(二)》),我們討論瞭如何為神經元搭建模型。雖然搭建模型的過程並不複雜,但得到的神經元模型也沒有太多的新意,比如使用sigmoid函式作為啟用函式,則得到的神經元模型就是邏輯迴歸。 在人體中