標籤:c# socket 粘包 斷包
一直是用JAVA,關於SOCKET方面,JAVA有一個不錯的架構MINA2,對於粘包、斷包的處理有這個良好的處理,個人需要寫的代碼並不太多。
而C#、因為瞭解不多,也沒去看第三方的SOCKET架構,所以只好根據MSDN提示,自己去實現了。
在代碼之前,我們先說說處理中會碰到的情況如何:
1、先假設資料包的格式如下:
包長度(4位元組)MD5簽名(32位元組)用戶端ID(5位元組)資料類型(5位元組)資料ID(32位元組)資料內容(動態長度、不固定)
|--------------------------------包頭78位元組--------------------------------------|------包體-----------------|
2、接收資料包時,可能會遇到的問題(假設,每次接收的緩衝區為1024位元組):
A、一次就接收到一個完整的包,也即此完整的資料包長度少於1024位元組,並且無其他資料包的資料與這個包的資料粘在一起;
也即,此資料包的資料情況如下:
緩衝區:|--------------------------1024位元組----------------------|
資料包:|------資料包1------|
B、一個接收的資料中有幾個包的資料粘合在一起,也即如下:
緩衝區:|--------------------------1024位元組----------------------|
資料包:|------資料包1資料包2資料包3...資料包N------| //N個資料包資料連結在一起,但整體不超過1024個位元組
或者資料包:|------資料包1資料包2資料包3.....資料包N(部分資料)-----| //N個資料包資料連結在一起,最後一個包的資料為此資料包的一部分資料
C、一個接收的資料為一個包的部分資料,也即此包的資料長度大於1024個位元組,也即如下:
緩衝區:|--------------------------1024位元組----------------------|
資料包1:|-------------資料1(某資料包的部分資料)----------------| //某個資料包的部分資料
資料包2:|-------------資料2(某資料包的部分資料)----------------| //某個資料包的部分資料
..........
資料包N:|-------------資料N(某資料包的部分資料)--------| //某個資料包的最後一部分資料,而後面無其他資料包的資料黏在一起
D、一個接收的資料為一個包的部分資料,也即此包的資料長度大於1024個位元組,也即如下:
緩衝區:|--------------------------1024位元組----------------------|
資料包1:|-------------資料1(某資料包的部分資料)----------------| //某個資料包的部分資料
資料包2:|-------------資料2(某資料包的部分資料)----------------| //某個資料包的部分資料
..........
資料包N:|-------------資料N(某資料包的部分資料)另一個包的資料--| //某個資料包的最後一部分資料,後面有其他資料包的資料黏在一起
3、處理方式:
第一次接收的時候,肯定可以接收到包括描述當前資料包長度的資訊,通過解析還原此資訊,就可以對比此次資料包的長度與緩衝區的長度,看是屬於上述(第二點)的哪一種類型,根據不同的類型,進行相應的處理:
A、類型A,這個情況處理最簡單,根據資料包的長度資訊,接收並解析資料即可
B、類型B,這種情形得分兩個情況處理,不過首先的先得獲得緩衝區的資料,然後
1)當N個資料包長度不超過1024位元組時:
通過遞迴,根據每一個包的長度來解析出每一個包的資訊就好了
2)當緩衝區的最後一部分資料還有某個包的部分資料時(暫稱:資料包X的部分資料A1),那就又得分兩種情況處理了:
I、資料包X的部分資料A1的長度大於等於4位元組的,也即包括了資料包X的長度資訊,並儲存這個部分資料A1,並獲得資料包X的長度
在下一次接收的時候,需要將剛才儲存的資料與這次接收的資料進行粘合,然後在根據之前獲得的長度進行處理
II、資料包X的部分資料A1的長度小於4位元組的,那就先儲存這個部分資料A1
在下一次接收的時候,需要將剛才儲存的資料與這次接收的資料進行粘合,並解析出這個包的長度,然後根據這個長度去處理
當然,這I,II兩個類型,都可以安裝II這個方式處理
C、類型C,這個情況,需要進行記錄兩個資訊,一個是這個資料包的長度,另外一個就是這個包的資料。
1)先獲得這個資料包的第一部分資料,儲存,然後解析出這個包的長度
2)繼續接收資料,並粘合之前儲存的資料,直到完成這個資料包所有的資料接收,然後解析這個資料包
D、類型D,這個情況是類型C與類型B的混合體
1)先根據類型C的方式進行資料儲存,然後根據這個資料包的長度,來解析資料包
2)然後根據類型B的情況,接收緩衝區最後一部分的資料、也即下一個資料包的部分資料,然後根據類型B的情況進行處理
C# SOCKET 粘包、斷包處理(一)