RPC里面的序列化反序列化以及拆包粘包


1.序列化
(1)什么是序列化?
Java的序列化是把對象轉換成有序字節流的過程。以便進行網絡傳輸或者保存到本地。
(2)為什么要序列化?
當兩個進程進行遠程通信時,如果需要發送各種各樣的數據,文本、音頻、文件、對象等,
在發送這些數據之前,都要把這些數據變成二進制流,才能在網絡上進行傳輸,序列化就
是把這些數據變成有序字節流的過程。

2.序列化工具
(1)Java原生序列化
缺點:
無法跨語言
序列化之后結果太大
序列化效率差
(2)Hessian

(3)thrift
(4)JBoss Marshalling
(5)kryo
(6)MessagePack、kryo、hession和Json

編碼和解碼
3.TCP的拆包和粘包
先看兩個應用場景:
(1)客戶端和服務端建立一個連接,客戶端發送一條消息,各戶端關閉與服務端的連接
(2)客戶端和服務端建立一個連接,客戶端發一條消息,客戶端再次發送消息,客戶端關閉與服務端的連接

 

I. 正常包:對於第一種情況,服務端在不停接收客戶端傳過來的數據,當客戶端斷開連接后,服務端知道數據接收完了,開始處理。

II.粘包:對於第二種情況,服務端就讀到了一個數據包,如果還是用同一個邏輯處理就有問題了,因為服務端會把兩條消息按照一條消息來處理。它不知道第一條
消息在哪結束,第二條消息從哪開始,即兩條消息被放到了同一個數據包,這種情況就叫做粘包

III.拆包:服務器收到了兩個數據包,第一個數據包只包含了第一條消息的一部分,第二個數據包含了第一條消息的一部分和第二條消息全部,
即同一條消息被拆到兩個數據包發送了,這種情況就叫做拆包

產生拆包和粘包的原因:
3個前置知識點:
I. tcp是以流動的方式傳輸數據,傳輸的最小單位是報文段(Segment)。
II. tcp Header中有個Option標識位,常見的標識叫mss(Max Segment Size),意思是連接層每次傳輸數據的最大限制(MTU),一般是1500bit,超過這個
數字要分成多個報文段去傳輸,mss則是最大限制減去Header的長度,就是只是數據包的大小,大約是1460bit,也就是180字節(B)
III. tcp為提高性能,會把要發送的數據先放到網絡緩沖區(大小可在程序里設定),等緩沖區滿了之后,再將緩沖區中的數據發送到接收方,同理接收方也有緩沖區這樣的機制來接收數據。

拆包:應用程序寫入緩沖區的消息,大於緩沖區的大小,一次寫不完,即一條消息要分到多個數據包來寫,就發生的拆包;
或者:進行mss(最大報文長度分段),當tcp報文長度 - Header > mss時,也會發生拆包。
粘包:應用程序一次寫入緩沖區的消息小於緩沖區的大小,緩沖區等下一個或多個消息寫入,寫滿之后,發到服務端,即一個數據包里有多條消息,就發生的拆包
或者:接收方未及時讀取緩沖區的內容,導到緩沖區有多條消息,就導致粘包
一個緩沖區可以有多個segment,如果segment和緩沖區大小相等,segment里面報文長度也剛好是一條消息,這時候不會發生拆包或粘包。


如何解決拆包的粘包呢?
方法I: 使用帶消息頭的協議,消息頭存儲消息開始標識和消息長度,服務端獲取到消息頭時,解析出消息長度,然后后后讀取該消息內容,如:0000000036{"type":"message","content":"hello"}
方法II: 設置定長消息,服務端每次讀取即定長度為一條消息。報文大小固定長度,不夠空格補全,發送和接收方遵循相同的約定,這樣即使粘包了通過接收方編程實現獲取定長報文也能區分。https://blog.csdn.net/zbw18297786698/article/details/53678323
方法III: 設置消息邊界,服務端按消息邊界從網絡流中讀取內容。比如:{"type":"message","content":"hello"}\n


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM