【问题标题】:How do I determine when there is no more data to read in a NetworkStream?如何确定何时没有更多数据可以在 NetworkStream 中读取?
【发布时间】:2008-09-21 15:10:21
【问题描述】:

我有一个 Web 应用程序,它使用 TCP 连接连接到服务器并读取二进制文档,然后将其写入其响应对象。换句话说,它使用自定义协议从后端服务器传输文件,并通过 HTTP 将该文件返回给客户端。

服务器发送一个状态码和一个mime类型,我读取成功然后写入文件内容并关闭套接字。这似乎工作正常。

客户端(C# Web 应用)读取数据:

     private NetworkStream stream_;

     public void WriteDocument(HttpResponse response)
     {
        while (stream_.DataAvailable)
        {
           const int bufsize = 4 * 1024;
           byte[] buffer = new byte[bufsize];
           int nbytes = stream_.Read(buffer, 0, bufsize);
           if (nbytes > 0)
           {
              if (nbytes < bufsize)
                 Array.Resize<byte>(ref buffer, nbytes);
              response.BinaryWrite(buffer);
           }
        }
        response.End();
     }

这似乎总是在所有数据到达之前退出读取循环。我做错了什么?

【问题讨论】:

    标签: c# networkstream


    【解决方案1】:

    我会直接将OutputStream 与通用功能一起使用。使用Stream,您可以控制Flush。

        public void WriteDocument(HttpResponse response) {
            StreamCopy(response.OutputStream, stream_);
            response.End();
        }
    
        public static void StreamCopy(Stream dest, Stream src) {
            byte[] buffer = new byte[4 * 1024];
            int n = 1;
            while (n > 0) {
                n = src.Read(buffer, 0, buffer.Length);
                dest.Write(buffer, 0, n);
            }
            dest.Flush();
        }
    

    【讨论】:

      【解决方案2】:

      这就是我所做的。通常希望内容长度知道何时结束数据存储循环。如果您的协议没有发送预期作为标头的数据量,那么它应该发送一些标记来表示传输结束。

      DataAvailable 属性只是表示现在是否有数据要从套接字读取,它不(也不能)知道是否还有更多数据要发送。要检查套接字是否仍然打开,您可以测试 stream_.Socket.Connected && stream_.Socket.Readable

          public static byte[] doFetchBinaryUrl(string url)
          {
              BinaryReader rdr;
              HttpWebResponse res;
              try
              {
                  res = fetch(url);
                  rdr = new BinaryReader(res.GetResponseStream());
              }
              catch (NullReferenceException nre)
              {
                  return new byte[] { };
              }
              int len = int.Parse(res.GetResponseHeader("Content-Length"));
              byte[] rv = new byte[len];
              for (int i = 0; i < len - 1; i++)
              {
                  rv[i] = rdr.ReadByte();
              }
              res.Close();
              return rv;
          }
      

      【讨论】:

      • 我真的做不到。返回的数据是二进制的,所以我不能真正使用任何类型的标记。而且它是动态生成的,可能相当大,所以我不想缓冲它,直到我知道它的大小。
      • 我希望 DataAvailable 表明服务器没有关闭套接字。
      • 如果套接字关闭,它会抛出异常,但也可能发生套接字打开但没有更多数据到达的情况。
      【解决方案3】:

      不确定 .Net 中的工作原理,但在我工作过的大多数环境中,Read() 在连接关闭时返回 0 字节。所以你会做这样的事情:

      字符缓冲区[4096]; 整数读; 而 ( num_read = src.Read(sizeof(buffer)) > 0 ) { dst.Write(buffer, num_read); }

      【讨论】:

        【解决方案4】:

        你的问题的根源是这一行:

        while (stream_.DataAvailable)
        

        DataAvailable 仅表示流缓冲区中有数据可供读取和处理。它不能保证已经到达流的“结束”。特别是,如果传输中有任何暂停,或者如果您的发件人比您的阅读器慢,则 DataAvailable 可能是错误的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-09-18
          • 1970-01-01
          • 2018-01-07
          • 2012-07-16
          • 2011-12-11
          • 2015-02-04
          相关资源
          最近更新 更多