6

TCPClient.Read() が送信されたすべてのバイトを 1 回の読み取りで取得できない可能性があるという記事を読みました。これをどのように説明しますか?

たとえば、サーバーは文字列を tcp ストリームに書き込むことができます。クライアントは文字列のバイトの半分を読み取り、別の読み取り呼び出しで残りの半分を読み取ります。

両方の呼び出しで受信したバイト配列をいつ結合する必要があるかをどのように判断しますか?

4

3 に答える 3

18

両方の呼び出しで受信したバイト配列をいつ結合する必要があるかをどのように判断しますか?

これは、プロトコル レベルで決定する必要があります。4 つの一般的なモデルがあります。

  • Close-on-finish: 各側は、接続ごとに 1 つの「メッセージ」のみを送信できます。メッセージの送信後、ソケットの送信側を閉じます。受信側は、ストリームの最後に到達するまで読み取りを続けます。
  • 長さのプレフィックス: 各メッセージの前に、メッセージのバイト数を含めます。これは、固定長形式 (例: 常に 4 バイト) または圧縮形式 (例: 1 バイトあたり 7 ビットのサイズ データ、サイズ データの最後のバイトに設定されたトップ ビット) のいずれかです。次に、メッセージ自体があります。受信コードはサイズを読み取り、そのバイト数を読み取ります。
  • チャンキング: 長さのプレフィックスと同様ですが、より小さなチャンクになります。各チャンクには長さがプレフィックスされ、最後のチャンクは「メッセージの終わり」を示します
  • メッセージ終了シグナル: メッセージのターミネータが表示されるまで読み続けます。メッセージ内のターミネータ データを表すためにエスケープ メカニズムを含める必要があるため、メッセージに任意のデータを含めることができる必要がある場合、これは面倒です。

さらに、あまり一般的ではありませんが、各メッセージが常に特定のサイズであるプロトコルがあります。この場合、それだけの量のデータを読み取るまで続行する必要があります。

これらのすべての場合において、基本的には、データが十分になるまで、ある種のバッファーにデータを読み取ってループする必要がありますが、それはあなたが決定します。常にの戻り値を使用して、実際Readに読み取ったバイト数を記録し、それが 0 であるかどうかを常に確認する必要があります。0 の場合、ストリームの最後に到達したことになります。

また、これはネットワーク ストリームだけに影響するわけではないことに注意してください。ローカル以外の場合MemoryStream(ストリーム内にある場合は、一度に必要なだけのデータを常に読み取ります)、データは複数の通話の過程で利用可能になります。

于 2012-09-26T06:08:21.237 に答える
-1

read()ループで呼び出す必要があります。そのループの条件は、まだ読み取り可能なデータがあるかどうかをチェックします。

于 2012-09-26T06:09:49.767 に答える
-3

データがいつ到着するかを知ることはできないため、答えるのはちょっと難しいです。そのため、私は通常、チャット プログラムでデータを受信するためにスレッドを使用します。ただし、次のようなものを使用できるはずです。

do{
     numberOfBytesRead = myNetworkStream.Read(myReadBuffer,
                                              0, 
                                              myReadBuffer.Length);

     myCompleteMessage.AppendFormat("{0}",
      Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));

  }
  while(myNetworkStream.DataAvailable);

このソースを見てください!

于 2012-09-26T06:11:15.513 に答える