2016-06-25 18 views
1

我正在使用C#套接字類通過短連接向/從我們的服務器發送/接收TCP消息。僞代碼(排除一些錯誤的容錯邏輯來說明)如下。當TCP包大於MTU時,C#Socket.Receive()出現故障

class MyTCPClient { 
    private Socket mSocket; 

    MyTCPClient() { 
     mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
    } 

    void Connect(ipEndpoint, sendTimeOut, receiveTimeOut) { 
     mSocket.Connect(ipEndpoint); 
     mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, sendTimeOut); 
     mSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, receiveTimeOut); 
    } 

    void Send(msg) { 
     mSocket.Send(msg); 
    } 

    void Receive(data) { 
     ByteStreamWriter bsw = new ByteStreamWriter(); 
     int totalLen = 0; 
     while (true) { 
      byte[] temp = new byte[1024]; 
      int len = mSocket.Receive(temp, SocketFlags.None); 
      System.Threading.Thread.Sleep(50); // This is the weirdest part 
      if (len <= 0) break; 
      totalLen += len; 
      bsw.WriteBytes(temp); 
     } 
     byte[] buff = bsw.GetBuffer(); 
     data = new byte[totalLen]; 
     Array.Copy(buff, 0, data, 0, totalLen); 
    } 

    ~MyTCPClient() { 
     mSocket.Close(); 
    } 
} 

我用這個類從我們的服務器幾次通過短的連接請求相同的消息,並且下面的事情發生(僅當消息大小是大於一個MTU - 1500個字節)。如果「睡眠(50)」被註釋掉,大部分時間(90%)我收到錯誤的「數據」,具體來說,「totalLen」是正確的,但是「數據」錯了。

  • 如果我將「睡眠(50)」換成「睡眠(10)」,大約一半的時間我收到錯誤的「數據」和「totalLen」也是正確的。
  • 如果我使用「睡眠(50)」,偶爾會收到錯誤的「數據」。我可以保證,我們的服務器每次都發送正確的數據,並且客戶端也在TCP層(我使用WireShark通過我使用的端口監視所有消息)接收到正確的數據。有沒有人可以幫助解答爲什麼我的C#代碼無法獲得正確的數據?

    另外,如果我用mSocket.Available代替Socket.Receive()的返回值來判斷while循環,我總是會得到正確的數據和數據長度...

  • +0

    是什麼*錯誤的數據*是什麼意思?你得到很多零?或垃圾?那個ByteStreamWriter從哪裏來?那是一個BinaryWriter嗎? – rene

    +0

    您不太瞭解TCP如何運作。 TCP將消息分解爲最大大小爲1500字節的數據報。網絡庫使用定時器,因此數據報可以進一步拆分或組合。 TCP還會發送零字節的消息,用作保持活動狀態,以便連接不會關閉。因此,在發送消息時,您必須爲每條消息設置一個終止符。您可以使用3種技術的組合:1)ASCII:以固定字符終止,如'\'2)Ascii或Binary:將消息的長度添加到消息的開頭3)Ascii或Binary:固定長度的消息。接收需要閱讀消息,直到找到結尾 – jdweng

    +0

    @rene對不起,我沒有表達得很清楚。錯誤的數據意味着垃圾,垃圾每次都從第二個TCP數據報的第一個字節開始。 ByteStreamWriter是一個非常簡單的BinaryWriter,我可以保證它按預期工作。 –

    回答

    2

    你不在寫入之前截取templen字節。 lentemp之後的所有字節都沒有填充當前數據,因此包含無意義的過期日期。

    當複製到另一個流,你可以使用stream.Write(temp, 0, len)

    +0

    非常感謝! –