代码之家  ›  专栏  ›  技术社区  ›  Ferruccio

如何确定网络流中没有更多数据可供读取?

  •  3
  • Ferruccio  · 技术社区  · 16 年前

    我有一个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();
         }
    

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

    4 回复  |  直到 16 年前
        1
  •  3
  •   Frank Krueger    16 年前

    我会用 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
  •  2
  •   Vinko Vrsalovic    16 年前

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

    dataavailable属性只是表示如果现在有数据要从套接字中读取,它不知道(也不知道)是否有更多的数据要发送。要检查套接字是否仍然打开,可以测试stream_u.socket.connected&stream_u.socket是否可读。

        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;
        }
    
        3
  •  1
  •   m_eiman    16 年前

    不确定在.NET中是如何工作的,但是在大多数环境中,当连接关闭时,我在read()中工作的返回0字节。所以你会做一些类似的事情:

    char buffer[4096];
    int num_read;
    
    while ( num_read = src.Read(sizeof(buffer)) > 0 )
    {
       dst.Write(buffer, num_read);
    }
    
        4
  •  1
  •   Roddy    16 年前

    问题的根源在于这一行:

    while (stream_.DataAvailable)
    

    dataavailable仅仅意味着流缓冲区中有数据可以读取和处理。它不能保证河流的“终点”已经到达。特别是,如果传输过程中有任何停顿,或者如果发送者比您的读卡器慢,那么可用数据可能是假的。