web-dev-qa-db-ja.com

NetworkStreamからすべてのデータを取得する方法

TCP/IPを介して接続されたマシンのバッファーに存在するすべてのデータを読み取ろうとしていますが、なぜすべてのデータを取得できないのかわからず、一部のデータが失われています。ここに私が使用しているコードがあります。

using (NetworkStream stream = client.GetStream())
{
    byte[] data = new byte[1024];
    int numBytesRead = stream.Read(data, 0, data.Length);
    if (numBytesRead > 0)
    {
       string str= Encoding.ASCII.GetString(data, 0, numBytesRead);
    }
}

マシンからすべてのデータを取得するために欠けているものを教えてください。前もって感謝します..

12
shubham Hegdey

コードの問題は、データサイズがバッファーサイズ(この場合は1024バイト)より大きい場合、すべてのデータを取得できないため、ループ内でストリームを読み取る必要があることです。次に、Writeの最後まで、MemoryStream内のすべてのデータをNetworkStreamできます。


      string str;
      using (NetworkStream stream = client.GetStream())
      {
            byte[] data = new byte[1024];
            using (MemoryStream ms = new MemoryStream())
            {

                int numBytesRead ;
                while ((numBytesRead = stream.Read(data, 0, data.Length)) > 0)
                {
                    ms.Write(data, 0, numBytesRead);


                }
               str = Encoding.ASCII.GetString(ms.ToArray(), 0, (int)ms.Length);
            }
        }
21
GeorgeChond

この MSDN:NetworkStream.DataAvailable の例は、そのプロパティを使用してそうする方法を示しています。

// Examples for CanRead, Read, and DataAvailable. 
// Check to see if this NetworkStream is readable. 
if(myNetworkStream.CanRead)
{
    byte[] myReadBuffer = new byte[1024];
    StringBuilder myCompleteMessage = new StringBuilder();
    int numberOfBytesRead = 0;

    // Incoming message may be larger than the buffer size. 
    do{
         numberOfBytesRead = myNetworkStream.Read(myReadBuffer, 0, myReadBuffer.Length);

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

    }
    while(myNetworkStream.DataAvailable);

    // Print out the received message to the console.
    Console.WriteLine("You received the following message : " +
                                 myCompleteMessage);
}
else
{
     Console.WriteLine("Sorry.  You cannot read from this NetworkStream.");
}
6
dariogriffo

これを試して:

 private string GetResponse(NetworkStream stream)
    {
        byte[] data = new byte[1024];
        using (MemoryStream memoryStream = new MemoryStream())
        {
            do
            {
                stream.Read(data, 0, data.Length);
                memoryStream.Write(data, 0, data.Length);
            } while (stream.DataAvailable);

            return Encoding.ASCII.GetString(memoryStream.ToArray(), 0, (int)memoryStream.Length);
        }
    }
2
Popa Andrei

このコードを試してください:

using (NetworkStream stream = client.GetStream())
    {
         do
         {
           Thread.Sleep(20);
         } while (!stream.DataAvailable);

         if (stream.DataAvailable && stream.CanRead)
         {
              Byte[] data = new Byte[1024];
              List<byte> allData = new List<byte>();

              do
              {
                    int numBytesRead = stream.Read(data,0,data.Length);

                    if (numBytesRead == data.Length)
                    {
                         allData.AddRange(data);
                    }
                    else if (numBytesRead > 0)
                    {
                         allData.AddRange(data.Take(bytes));
                    }                                    
               } while (stream.DataAvailable);
          }
    }

これがお役に立てば幸いです。送信されたデータを見逃すのを防ぐはずです。

2
Paul Weiland

私のシナリオでは、メッセージ自体が後続のメッセージの長さを示していました。ここにコードがあります

 int lengthOfMessage=1024;
 string message = "";
 using (MemoryStream ms = new MemoryStream())
 {
      int numBytesRead;
      while ((numBytesRead = memStream.Read(MessageBytes, 0, lengthOfMessage)) > 0)
      {
            lengthOfMessage = lengthOfMessage - numBytesRead;
            ms.Write(MessageBytes, 0, numBytesRead);
      }
      message = Encoding.ASCII.GetString(ms.ToArray(), 0, (int)ms.Length);
 }
0
Asad Durrani

TCP自体には、「データの終わり」条件を定義する方法がありません。これはアプリケーションレベルのportocolの責任です。

たとえば [〜#〜] http [〜#〜] リクエストの説明をご覧ください:

クライアント要求(この場合、要求行と1つのヘッダーフィールドのみで構成される)の後には空白行が続くため、要求は二重の改行で終了します。

したがって、要求のデータの終わりは、2つの改行シーケンスによって決定されます。そして応答のために:

Content-Typeは、HTTPメッセージによって伝達されるデータのインターネットメディアタイプを指定し、Content-Lengthはその長さをバイト単位で示します。

応答コンテンツのサイズは、データの前のヘッダーで指定されます。したがって、一度に転送されるデータの量をエンコードする方法はあなた次第です。読み取る必要がある場合は、合計サイズを保持するデータの最初の2バイトまたは4バイトか、より複雑な方法にすることができます。

0
dewaffled

この質問に少し遅れて参加しましたが、私はそれを行う最も卑近な方法が何であるか自分自身に疑問を抱いていました。プロトコルが不明な場合..これが私の結論です

前の回答で述べたwhileループはNetworkStreamでは正しく機能せず、失敗してデータがまったく得られません。

私はDataAvailableを試したことがなく、それがどのように機能するかわからないので、誰でも理解できるバージョンを好みます。

var ms = new MemoryStream();
byte[] data = new byte[1024];
int numBytesRead;

do
{
    numBytesRead = stream.Read(data, 0, data.Length);
    ms.Write(data, 0, numBytesRead);

} while (numBytesRead == data.Length);

var str = Encoding.ASCII.GetString(ms.ToArray());
0
Johan Sonesson

同期メソッドは、リクエストの本文を表示しない場合があります。非同期メソッドを使用すると、リクエストの本文が安定して表示されます。

string request = default(string);
StringBuilder sb = new StringBuilder();

byte[] buffer = new  byte[client.ReceiveBufferSize];
int bytesCount;

if (client.GetStream().CanRead)
{
    do
    {
        bytesCount = client.GetStream().ReadAsync(buffer, 0, buffer.Length).Result;
        sb.Append(Encoding.UTF8.GetString(buffer, 0, bytesCount));
    }
    while(client.GetStream().DataAvailable);

    request = sb.ToString();
}
0
shmnff