如何从NetworkStream获取所有数据

问题描述 投票:0回答:8

我正在尝试读取通过

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);
    }
}

请告诉我从机器获取所有数据时缺少什么。 预先感谢..

c# tcpclient tcp networkstream
8个回答
28
投票

您的代码的问题是,如果数据大小大于缓冲区大小(在您的情况下为 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);
            }
        }

11
投票

来自 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.");
}

2
投票

试试这个:

 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
投票

试试这个代码:

using (NetworkStream stream = client.GetStream())
    {
         while (!stream.DataAvailable)
         {
             Thread.Sleep(20);
         }
        
         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(numBytesRead));
                    }                                    
               } while (stream.DataAvailable);
          }
    }
      

希望这有帮助,它应该可以防止您错过发送给您的任何数据。


2
投票

同步方法有时不显示请求体。使用异步方法总是可以的。

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
投票

TCP本身没有任何方法来定义“数据结束”条件。这是应用程序级别 portocol 的责任。

例如参见HTTP请求描述:

客户端请求(在本例中由请求行和仅一个标头字段组成)后面跟着一个空行,因此请求以双换行符结束

因此,对于请求数据的结束是由两个换行序列确定的。并回复:

Content-Type 指定 HTTP 消息传送的数据的互联网媒体类型,而 Content-Length 表示其长度(以字节为单位)。

响应内容大小在数据之前的标头中指定。 因此,如何对一次传输的数据量进行编码取决于您 - 它可以是数据开头的前 2 或 4 个字节,用于保存要读取的总大小,也可以根据需要采用更复杂的方式。


0
投票

对于我的场景,消息本身告诉了后续消息的长度。这是代码

 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
投票

@George Chondrompilas 答案是正确的,但您可以使用具有相同功能的 CopyTo 函数,而不是自己编写它:

https://stackoverflow.com/a/65188160/4120180

© www.soinside.com 2019 - 2024. All rights reserved.