TCP無保護訊息邊界的解決

來源:互聯網
上載者:User

     我們都知道,TCP協議是面向流的。面向流是指無保護訊息邊界的,如果發送端連續發送資料,接收端有可能在一次接收動作中會接收兩個或者更多的資料包。

      那什麼是保護訊息邊界呢?就是指傳輸協議把資料當做一條獨立的訊息在網上傳輸,接收端只能接收獨立的訊息。也就是說存在保護訊息邊界,接收端一次只能接收發送端發出的一個資料包。

     舉個例子來說,連續發送三個資料包,大小分別是1k,2k,4k,這三個資料包都已經到達了接收端的緩衝區中,如果使用UDP協議,不管我們使用多大的接收緩衝區去接收資料,則必須有三次接收動作,才能把所有資料包接受完。而使用TCP協議,只要把接收資料的緩衝區大小設定在7kb以上,就能夠一次把所有的資料包接收下來,即只需要有一次接收動作。

     這樣問題就來了,由於TCP協議是流傳輸的,它把資料當作一串資料流,所以他不知道訊息的邊界,即獨立的訊息之間是如何被分隔開的。這便會造成訊息的混淆,也就是說不能夠保證一個Send方法發出的資料被一個Recive方法讀取。在講解緩衝區的時候,我們已經講過Recive方法是從系統緩衝區上讀取資料的,所以只要資料緩衝區的容量足夠大,該方法不單單接收第一個包的資料,可能是所有的資料。

      例如,有兩台網路上的電腦,客戶機發送的訊息是:第一次發送abcde,第二次發送12345,伺服器方接收到的可能是abcde12345,即一次性收完;也可能是第一次接收到abc,第二次接收到de123,第三次接收到45.

      針對這個問題,一般有3種解決方案:

      (1)發送固定長度的訊息

      (2)把訊息的尺寸與訊息一塊發送

      (3)使用特殊標記來區分訊息間隔

      

下面我們主要分析下前兩種方法:

 

1、發送固定長度的訊息
這種方法的好處是他非常容易,而且只要指定好訊息的長度,沒有遺漏未未發的資料,我們重寫了一個SendMessage方法。代碼如下:

  private static int SendMessage(Socket s, byte[] msg)

        { 
            int offset = 0; 
            int size = msg.Length; 
            int dataleft = size; 

            while (dataleft > 0) 
            {

                int sent = s.Send(msg, offset, SocketFlags.None); 
                offset += sent; 
                dataleft -= sent;

            }

            return offset; 
        }

簡要分析一下這個函數:形參s是進行通訊的通訊端,msg即待發送的位元組數組。該方法使用while迴圈檢查是否還有資料未發送,尤其當發送一個很龐大的資料包,在不能一次性發完的情況下作用比較明顯。特別的,用sent來記錄實際發送的資料量,和recv是異曲同工的作用,最後返回傳送的實際資料總數。

   有sentMessage函數後,還要根據指定的訊息長度來設計一個新的Recive方法。代碼如下:

  private byte[] ReciveMessage(Socket s, int size) 
        { 

            int offset = 0; 
            int recv; 
            int dataleft = size; 
            byte[] msg = new byte[size]; 

            while (dataleft > 0)

            {

                //接收訊息 
                recv = s.Receive(msg, offset, dataleft, 0); 
                if (recv == 0)

                {

                    break;

                } 
                offset += recv; 
                dataleft -= recv;

            }

            return msg;

        }

以上這種做法比較適合於訊息長度不是很長的情況。 

2、訊息長度與訊息一同發送

 

我們可以這樣做:通過使用訊息的整形數值來表示訊息的實際大小,所以要把整形數轉換為位元組類型。下面是發送變長訊息的SendMessage方法。具體代碼如下:

  private static int SendMessage(Socket s, byte[] msg) 
        {

            int offset = 0; 
            int sent; 
            int size = msg.Length; 
            int dataleft = size; 
            byte[] msgsize = new byte[2];

            //將訊息尺寸從整形轉換成可以發送的位元組型 
            msgsize = BitConverter.GetBytes(size); 

            //發送訊息的長度資訊 
            sent = s.Send(size);

            while (dataleft > 0)

            {

                sent = s.Send(msg, offset, dataleft, SocketFlags.None);

                //設定位移量

                offset += sent; 
                dataleft -= sent;

            }

            return offset;

        }

下面是接收變長訊息的ReciveVarMessage方法。代碼如下:

private byte[] ReciveVarMessage(Socket s) 
        { 

            int offset = 0; 
            int recv; 
            byte[] msgsize = new byte[2]; 

            //將位元組數組的訊息長度資訊轉換為整形 
            int size = BitConverter.ToInt16(msgsize); 
            int dataleft = size; 
            byte[] msg = new byte[size]; 

            //接收2個位元組大小的長度資訊 
            recv = s.Receive(msgsize, 0, 2, 0); 
            while (dataleft > 0) 
            {

                //接收資料 
                recv = s.Receive(msg, offset, dataleft, 0); 
                if (recv == 0) 
                { 
                    break; 
                } 
                offset += recv; 
                dataleft -= recv;

            }

            return msg;

        }

 

參考資料:http://aksnzhy.javaeye.com/blog/789049

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.