天天看點

C#高性能大容量SOCKET并發(五):粘包、分包、解包

粘包

使用TCP長連接配接就會引入粘包的問題,粘包是指發送方發送的若幹包資料到接收方接收時粘成一包,從接收緩沖區看,後一包資料的頭緊接着前一包資料的尾。粘包可能由發送方造成,也可能由接收方造成。TCP為提高傳輸效率,發送方往往要收集到足夠多的資料後才發送一包資料,造成多個資料包的粘連。如果接收程序不及時接收資料,已收到的資料就放在系統接收緩沖區,使用者程序讀取資料時就可能同時讀到多個資料包。 粘包一般的解決辦法是制定通訊協定,由協定來規定如何分包解包。

分包

在NETIOCPDemo例子程式中,我們分包的邏輯是先發一個長度,然後緊接着是資料包内容,這樣就可以把每個包分開。 應用層資料包格式如下: 應用層資料包格式 資料包長度Len:Cardinal(4位元組無符号整數) 資料包内容,長度為Len AsyncSocketInvokeElement分包處理主要代碼,我們收到的資料都是在ProcessReceive方法中處理,處理的方法是把收到的資料存到緩沖區數組中,然後取前4個位元組為長度,如果剩下的位元組數大于等于長度,則取到一個完整包,進行後續邏輯處理,如果取到的不夠一個包,則不處理,等待後續包接收,具體代碼如下:

解包

由于我們應用層資料包既可以傳指令也可以傳資料,因而針對每個包我們進行解包,分出指令和資料分别處理,因而每個Socket服務對象都需要解包,我們解包的邏輯是放在ProcessPacket中,指令和資料的包格式為: 指令長度Len:Cardinal(4位元組無符号整數) 指令 資料

每個包中包含多個協定關鍵字,每個協定關鍵字用回車換行分開,是以我們需要調用文本分開函數,然後針對每條指令解析出關鍵字和值,具體代碼在IncomingDataParser.DecodeProtocolText如下:

處理指令

解析出指令後,需要對每個指令進行處理,各個協定實作類從AsyncSocketInvokeElement.ProcessCommand繼承,然後編寫各自協定處理邏輯,如吞吐量的測試協定邏輯實作代碼如下: