如何确定 NetworkStream 中何时不再有数据可供读取?

发布于 2024-07-04 22:22:23 字数 800 浏览 13 评论 0原文

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

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

I have a web app which connects to a server using a TCP connection and reads a binary document which it then writes to its response object. In other words it's transferring a file from a backend server using a custom protocol and returning that file to its client through HTTP.

The server sends a status code and a mime type, which I read successfully and then writes the contents of the file and closes the socket. This seems to work fine.

The client (a C# web app), reads the data:

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

This seems to always exit the read loop before all the data has arrived. What am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

内心旳酸楚 2024-07-11 22:22:23

问题的根源是这一行:

while (stream_.DataAvailable)

DataAvailable 只是意味着流缓冲区中有数据可供读取和处理。 它不保证已到达流的“末尾”。 特别是,如果传输有任何暂停,或者如果您的发送方比您的阅读器慢,则 DataAvailable 可能为 false。

The root of your problem is this line:

while (stream_.DataAvailable)

DataAvailable simply means there's data in the stream buffer ready to be read and processed. It makes no guarantee about the 'end' of the stream having been reached. In particular, DataAvailable can be false if there's any pause in transmission, or if your sender is slower than your reader.

堇年纸鸢 2024-07-11 22:22:23

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

char buffer[4096];
int num_read;

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

Not sure how things work in .Net, but in most environments I've worked in Read() returns 0 bytes when the connection is closed. So you'd do something like:

char buffer[4096];
int num_read;

while ( num_read = src.Read(sizeof(buffer)) > 0 )
{
   dst.Write(buffer, num_read);
}
爱殇璃 2024-07-11 22:22:23

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

I would use the OutputStream directly with a general-purpose function. With the Stream, you can control 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();
    }
ゃ人海孤独症 2024-07-11 22:22:23

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

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

Here's what I do. Usually the content length is desired to know when to end the data storing loop. If your protocol does not send the amount of data to expect as a header then it should send some marker to signal the end of transmission.

The DataAvailable property just signals if there's data to read from the socket NOW, it doesn't (and cannot) know if there's more data to be sent or not. To check that the socket is still open you can test for 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;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文