【问题标题】:How to get all data from NetworkStream如何从 NetworkStream 获取所有数据
【发布时间】:2014-11-21 09:47:17
【问题描述】:

我正在尝试读取通过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);
    }
}

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

【问题讨论】:

  • 这可能与您明确读取最多 1024 个字节的事实有关吗?
  • @decPL Ok 那么我怎样才能读取所有数据呢?
  • 究竟缺少什么?流的开始、结束还是随机字节?你能从字节序列中识别出流的结尾吗?您知道数据的预期长度吗?
  • @Aik 它缺少随机字节。并且数据长度不知道它可以是任何东西?
  • 不,它不可能是任何东西。如果您不想等到客户端关闭连接,则需要定义一个协议。否则 - 继续阅读,直到客户端关闭连接。

标签: c# tcp tcpclient tcp-ip networkstream


【解决方案1】:

您的代码的问题是,如果数据大小大于缓冲区大小(在您的情况下为 1024 字节),您将无法获取所有数据,因此您必须读取循环内的流。然后你可以WriteMemoryStream里面的所有数据,直到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);
            }
        }

【讨论】:

  • 不,在 str 中,您将获得整个字符串,该字符串在您阅读时存储在 NetworkStream 中。
  • 你的意思是说缓冲区中所有可用的数据。对吗?
  • 在 NetworkStream 中使用 MemoryStream 也是一种可能的解决方案 :) +1 如果您想要一种使用您的代码并扩展它的方法,请检查其他答案。尝试调试您使用的代码并了解每一步发生的情况,这可能会对您有所帮助。
  • 我在 `while (numBytesRead = stream.Read(data, 0, data.Length) > 0)` 处出现错误,无法将 bool 转换为 int 并且 buffer 在当前不存在上下文和代码的最后一行Encoding.ASCII.GetString(ms.ToArray(), 0, ms.Length);
  • 小心。此解决方案在using 部分结束后关闭连接。
【解决方案2】:

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

【讨论】:

  • 这个例子是做什么的? NetworkStream.DataAvailable 对于 OP 的目的是否可靠?什么时候变成false
  • 当套接字中没有更多数据时我变为假,为什么不可靠?
  • 没有。 NetworkStream.DataAvailablefalse 只是表示接收器的接收缓冲区中没有数据。不代表发送方已经发送完毕,所以不能用来实现协议,也解决不了OP的问题。
  • 读你自己,你说我是对的,他要求读流中的所有数据。您正在超越一步,我同意您的看法,他需要实现一个协议,但这不是这里的问题,他问如何读取流中的所有数据。
  • 我非常怀疑这是 OP 想要的,但你是对的。
【解决方案3】:

试试这个:

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

【讨论】:

  • 我会将第 8 行和第 9 行分别替换为 var readCount = stream.Read(data, 0, data.Length);memoryStream.Write(data, 0, readCount);。这样一来,就不会得到尾随 0 字节,这些字节会在输出字符串中转换为 "\0" 空字符。
【解决方案4】:

试试这个代码:

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

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

【讨论】:

    【解决方案5】:

    同步方法有时不显示请求正文。使用异步方式稳定显示请求体。

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

    【讨论】:

      【解决方案6】:

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

      例如见HTTP请求描述:

      客户端请求(在这种情况下由请求行和一个头字段组成)后跟一个空行,因此请求以双换行符结束

      所以,对于请求数据的结束是由两个换行序列决定的。对于回应:

      Content-Type 指定 HTTP 消息所传达的数据的 Internet 媒体类型,而 Content-Length 表示其长度,以字节为单位。

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

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

          【解决方案8】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-08-26
            • 1970-01-01
            • 1970-01-01
            • 2020-09-13
            • 2014-12-15
            • 2015-09-10
            相关资源
            最近更新 更多