0

を介してデータを読み取るメソッドがあり、いくつかTcpClientNetworkStreamエラーが発生しています。

調査中に、実際には正常に機能することがわかりました...ただし、ブレークポイントを使用して、Visual Studio 2012 のデバッガーでコードをステップ実行した場合のみです。

これが私のコードです:

public static byte[] DownloadStream(string hostname, int port, 
    byte[] requestBytes, int bufferSize = 4096)
{
    byte[] responseBytes = null;

    var client = new System.Net.Sockets.TcpClient(hostname, port);

    if (client.Connected)
    {
        using (var stream = client.GetStream())
        {
            stream.Write(requestBytes, 0, requestBytes.Length);
            stream.Flush();

            if (stream.CanRead)
            {
                var responseStream = new System.IO.MemoryStream();

                byte[] buffer = new byte[bufferSize];
                int bytesRead = 0;

                do
                {
                    bytesRead = stream.Read(buffer, 0, buffer.Length);

                    responseStream.Write(buffer, 0, bytesRead);
                }
                while (stream.DataAvailable);

                responseBytes = responseStream.ToArray();
            }
        }
    }

    client.Close();

    return responseBytes;
}

実際のエラーがないため、これはかなりイライラします。を読み取る間、デバッガーが手を握るだけでよいようNetworkStreamです。

なぜこれが起こっているのか誰にも分かりますか?どうすれば修正できますか?


編集:

何らかの理由で、この変更を行うと問題が解消されます。

                do
                {
                    bytesRead = stream.Read(buffer, 0, buffer.Length);

                    responseStream.Write(buffer, 0, bytesRead);

                     System.Threading.Thread.Sleep(1); //added this line
                }
                while (stream.DataAvailable);

これに関する洞察はありますか?

4

1 に答える 1

4

NetworkStream.DataAvailableプロパティは、応答の終わりを検出するための信頼できる方法ではありません。応答が複数の TCP パケットに分割され、チェックした時点でまだパケットが配信されていない場合DataAvailable、プロパティは false を返し、ループを途中で終了させます。

どうやら、ネットワーク接続は十分に高速でThread.Sleep(1)、連続する各パケットが到着するのに十分な時間を提供しているようです。ただし、低速の接続では、十分でない場合があります。

信頼性の高い通信を行うには、クライアントとサーバーが応答の終了を通知する方法について合意する必要があります。例えば:

  • サーバーは、実際の応答の前に、応答の長さをプレフィックスとして送信できます。クライアントは長さを読み取り、そのバイト数を受け取るまでストリームから読み取ります。
  • サーバーは、実際の応答の後にサフィックスとして特別なターミネータを送信できます。クライアントは、ターミネータに遭遇するまでストリームから読み取ります。(明らかに、ターミネータは応答自体のどこにも表示できません。)
  • サーバーは、応答全体を送信した後、接続を閉じることができます。クライアントは、接続が閉じられるまでストリームから読み取ります。
于 2013-10-25T23:12:54.903 に答える