2016-06-25 3 views
1

私はC#ソケットクラスを使用して、短い接続でサーバーとの間でTCPメッセージを送受信しています。疑似コード(いくつかの誤った許容論理を除外して明確にする)は以下の通りです。TCPのパッケージがMTUより大きい場合に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(); 
    } 
} 

(メッセージのサイズが1つのMTUよりも大きくなったときにのみ - 1500バイト)私は、短い接続により当社のサーバーから複数回、同じメッセージを要求するために、このクラスを使用していた、と次のようなものが発生しました。

  1. 「スリープ(50)は」回(90%)のほとんどが、私は特に言うには、「totalLen」は正しかった、間違った「データ」を受信しますが、「データ」、コメントアウトされた場合間違っていました。
  2. 「スリープ(50)」を「スリープ(10)」に変更した場合、約半分の時間が間違った「データ」を受信し、「totalLen」も常に正しくなりました。
  3. 「スリープ(50)」を使用すると、間違った「データ」が受信されることがあります。

私たちのサーバーが適切なデータを送信し、クライアントがTCPレイヤーで適切なデータを受信することを保証できます(使用したポートを通じてすべてのメッセージを監視するWireSharkを使用しました)。なぜ私のC#コードが正しいデータを得ることができないのかを答えるのに役立つ人はいますか?私は常に正しいデータとデータの長さになるだろう。また

、私はwhileループを判断する代わりに、Socket.Receive()の戻り値のmSocket.Availableを使用する場合、...

+0

を使用することができますか?あなたはゼロをたくさん得ますか?またはごみですか?そして、ByteStreamWriterはどこから来たのですか?それはBinaryWriterですか? – rene

+0

あなたはTCPがどのように動作するかを本当に理解していません。 TCPはメッセージを最大サイズ〜1500バイトのデータグラムに分割します。ネットライブラリはタイマーを使用して、データグラムをさらに分割したり組み合わせたりすることができます。 TCPはキープアライブとして使用される0バイトのメッセージも送信し、接続が終了しないようにします。したがって、メッセージを送信する際には、メッセージごとにターミネータが必要です。あなたは3つの技術を組み合わせて使用​​することができます:1)ASCII:メッセージ3の先頭に長さを追加)ASCIIまたはバイナリ::固定長のメッセージ「'\」2)ASCIIまたはバイナリのような固定された文字で終了します。最後までメッセージを読む必要がある – jdweng

+0

@rene申し訳ありませんが、私は非常に明確に表現していません。間違ったデータはガベージを意味し、ガベージは常に2番目のTCPデータグラムの最初のバイトから正確に開始されます。 ByteStreamWriterは非常にシンプルなBinaryWriterです。期待通りに動作することを保証できます。 –

答えて

2

あなたはしないでください書き込む前にtemplenバイトを切り捨てます。 lenの後のすべてのバイトが現在のデータで満たされていないため、無意味で失効した日付が含まれています。別のストリームにコピーする場合

あなたは*誤ったデータが*何を意味するのstream.Write(temp, 0, len)

+0

ありがとう! –

関連する問題