如何确定何时无法在NetworkStream中读取数据?

时间:2008-09-21 15:10:21

标签: c# networkstream

我有一个使用TCP连接连接到服务器的Web应用程序,并读取二进制文档,然后将其写入其响应对象。换句话说,它使用自定义协议从后端服务器传输文件,并通过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 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

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

DataAvailable属性只是表示是否有数据要从套接字中读取,它不会(也不能)知道是否有更多数据需要发送。要检查套接字是否仍处于打开状态,您可以测试stream_.Socket.Connected&amp;&amp; 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;
    }

答案 2 :(得分:1)

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

char buffer[4096];
int num_read;

while ( num_read = src.Read(sizeof(buffer)) > 0 )
{
   dst.Write(buffer, num_read);
}

答案 3 :(得分:1)

问题的根源是这一行:

while (stream_.DataAvailable)

DataAvailable只是意味着流缓冲区中的数据已准备好进行读取和处理。它无法保证已到达流的“结束”。特别是,如果传输中有任何暂停,或者发件人比读者慢,则DataAvailable可能为false。