Socket 迴圈接收訊息 粘包 半包(C#)
阿新 • • 發佈:2019-02-16
這兩天在向同事學習socket收發訊息的問題,學到了新知識,非常感謝 yss 的 hwh
1、對於一次接收到大於接收快取的訊息,並且連續接收訊息,兩段訊息可能同時被接受到一端快取中,叫粘包;
2、收到的訊息不足一個接收快取,交半包;
程式的幾個注意點:
1、必須要迴圈接收訊息;
2、訊息頭必須要有長度標誌位元組(這裡是用的前四個位元組來儲存實際訊息體的長度);
3、除了接收快取rev之外還需要一個cache快取byte[] ,用來儲存一條完整的訊息;
4、cache快取可能不足一個接收快取,那後面不足的會有\0 補充 ,半包;
5、cache快取 可能剛好一個接收快取,並且包含>= 1個完整訊息(等於的時候無粘包,大於的時候有粘包);
6、cache快取 大於一個接收快取,這裡需要迴圈接收(用長度標誌位元組來判斷),直到接收到 >= 一個完整訊息,還是5、的情況;
7、接受完一個完整訊息後,需要清空快取,或者將有粘包的位元組重新拷貝到cache快取;
以下是程式碼實現:
Socket soc = obj as Socket; int recvlen = 0; byte[] cacheBuf = null; byte[] recvBuf = new byte[100]; if (soc != null) { while ((recvlen = soc.Receive(recvBuf)) > 0) { if (cacheBuf == null) { cacheBuf = new byte[recvlen]; Array.Copy(recvBuf, cacheBuf, recvlen); } else { byte[] t = new byte[cacheBuf.Length + recvlen]; Array.Copy(cacheBuf, t, cacheBuf.Length); Array.Copy(recvBuf, 0, t, cacheBuf.Length, recvlen); cacheBuf = t; } if (cacheBuf.Length <= 4) continue; int msgl = BitConverter.ToInt32(cacheBuf, 0); while (cacheBuf!=null && msgl + 4 <= cacheBuf.Length) { byte[] msgbyte = new byte[msgl]; Array.Copy(cacheBuf, 4, msgbyte, 0, msgl); test(msgbyte,soc);//拿到完整訊息,具體訊息操作 if (msgl + 4 == cacheBuf.Length) { cacheBuf = null; } else { byte[] tmpByte = new byte[cacheBuf.Length - msgl - 4]; Array.Copy(cacheBuf, msgl + 4, tmpByte, 0, cacheBuf.Length - msgl - 4); cacheBuf = tmpByte; } } } }