1. 程式人生 > >解決粘包問題

解決粘包問題

sta pad readme accep ole 一個 exc spa Coding

粘包分包問題

# 如果使用異步方式 beginreceive() 如果開辟的數組足夠大,是不會產生分包發送的問題,但是- - 足夠大是多大….

上一篇寫了Socket通訊,這一篇整理一下粘包分包的問題, 主要思路是在字節數據前四個位置保存一個數據的長度後邊保存數據,通過一個類進行存儲傳輸過來的數據,再使用這個類進行解析.

服務器

namespace 服務器
{
//解析類
class Message
    {
        private byte[] date = new byte[10240];
        public int startIndex = 0; //存儲了多少字節的數據

        public byte[] Date
        {
            get { return date; }
        }

        public int ReMainSize//得到剩余date大小
        {
            get { return date.Length - startIndex; }
        }

        public void AddCount(int count) //添加數據
        {
            startIndex += count;
        }

        public void ReadMessage()
        {

            while (true)
            {
                if (startIndex <= 4) //如果不大於4表示數據可能不完整.則不解析
                    return;

                int count = BitConverter.ToInt32(date, 0); //將date中的前4個字節(當前數據完整的長度是多少)讀取到
                if ((startIndex - 4) >= count) //判斷剩余的字節夠不夠,
                {

                   // Console.WriteLine("count" + count);
                    string temp = Encoding.UTF8.GetString(date, 4, count); //如果夠, 讀取當前完整的記錄
                    Console.WriteLine("startIndex" + startIndex);
                    Console.WriteLine("解析出來一條數據:" + temp);
                    Array.Copy(date, count + 4, date, 0, startIndex - count - 4);// 復制當前數組到自己(就是替換) 把date數據,從已經解析的位置開始,賦值到自己,賦值到自己的0開始到剩余的數據長度
                    startIndex -= (count + 4); //把startIndex的位置向前提,(減去剛剛解析的數據長度)
                }
                else
                {
                    break;
                }

            }



        }

    }




    class Program
    {
        static void Main(string[] args)
        {
            Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            serverSocket.Bind(new IPEndPoint(IPAddress.Parse("10.6.0.38"), 88));

            serverSocket.Listen(19);

            serverSocket.BeginAccept(ClientAccept, serverSocket);//異步連接(回調函數,參數)
            Console.ReadLine();

        }
        //static byte[] buffer = new byte[1024];
        static Message msg = new Message();
        static void ClientAccept(IAsyncResult ar)
        {


            Socket serverSocket = ar.AsyncState as Socket;

            Socket clientSocket = serverSocket.EndAccept(ar);

            clientSocket.Send(Encoding.UTF8.GetBytes("hellooo"));

            clientSocket.BeginReceive(msg.Date, msg.startIndex, msg.ReMainSize, SocketFlags.None, ServerReceive, clientSocket);//(存儲到的數據,從第幾個位置開始存儲,向裏存的最大數量,標誌,回調,參數)這裏如果接收到的數據大於ReMainSize也不會超過這個ReMainSize,如果ReMainSize設置的太大, 大於接收到的數據,那麽存儲到msg.date中會報錯

            serverSocket.BeginAccept(ClientAccept, serverSocket);//在這裏繼續進行異步連接,有點遞歸的意思

        }

        static void ServerReceive(IAsyncResult ar)
        {
            Socket clientSocket = null;

            try
            {
                clientSocket = ar.AsyncState as Socket;
                int len = clientSocket.EndReceive(ar);

                if (len == 0)
                {
                    clientSocket.Close();
                    return;
                }
                msg.AddCount(len);

                msg.ReadMessage();//這裏註意先手順序, ↓這行代碼一定要在之後
                clientSocket.BeginReceive(msg.Date, msg.startIndex, msg.ReMainSize, SocketFlags.None, ServerReceive, clientSocket);//這裏如果接收到的數據大於ReMainSize也不會超過這個ReMainSize,如果ReMainSize設置的太大, 大於接收到的數據,那麽存儲到msg.date中會報錯

            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                clientSocket.Close();
            }


            Console.ReadLine();
        }
    }
}

客戶端

namespace 客戶端
{
    class Program
    {
        static byte[] GetBytes(string date)
        {
            byte[] dateBytes = Encoding.UTF8.GetBytes(date);
            int len = dateBytes.Length;
            byte[] byteLengths = BitConverter.GetBytes(len);
            byte[] newBytes = byteLengths.Concat(dateBytes).ToArray();
            return newBytes;
        }




        static void Main(string[] args)
        {

            byte[] buffer = new byte[1024];

            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            clientSocket.Connect(new IPEndPoint(IPAddress.Parse("10.6.0.38"), 88));

            int len = clientSocket.Receive(buffer);

            Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, len));

            //while (true)
            //{
            //    string temp = Console.ReadLine();

            //    if (temp == "c")
            //    {
            //        clientSocket.Close();
            //        return;
            //    }

            //    byte[] tempByte = Encoding.UTF8.GetBytes(temp);

            //    clientSocket.Send(tempByte);
            //}

            for (int i = 0; i < 100; i++)
            {
                clientSocket.Send(GetBytes(i.ToString()));
            }

            Console.ReadLine();

        }
    }
}

解決粘包問題