1. 程式人生 > >Socket 迴圈接收訊息 粘包 半包(C#)

Socket 迴圈接收訊息 粘包 半包(C#)

這兩天在向同事學習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;
                            }
                        }
                    }
                }