如何确定何时在NetworkStream中没有其他数据要读取?
时间:2020-03-06 14:30:27 来源:igfitidea点击:
我有一个Web应用程序,该应用程序使用TCP连接连接到服务器,并读取一个二进制文档,然后将其写入其响应对象。换句话说,它使用自定义协议从后端服务器传输文件,然后通过HTTP将文件返回给客户端。
服务器发送一个状态代码和一个mime类型,我成功读取了该状态代码,然后写入了文件的内容并关闭了套接字。这似乎工作正常。
客户端(一个Cweb应用程序)读取数据:
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(); }
这似乎总是在所有数据到达之前退出读取循环。我究竟做错了什么?
解决方案
这是我的工作。通常,希望知道内容长度以何时结束数据存储循环。如果协议没有发送期望作为报头的数据量,则它应该发送一些标记来表示传输结束。
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; }
我会直接将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(); }
不知道在.Net中如何工作,但是在大多数环境中,当连接关闭时,我在Read()中工作的返回0字节。因此,我们将执行以下操作:
char buffer[4096]; int num_read; while ( num_read = src.Read(sizeof(buffer)) > 0 ) { dst.Write(buffer, num_read); }
我们问题的根源是这一行:
while (stream_.DataAvailable)
DataAvailable只是意味着流缓冲区中有准备读取和处理的数据。它不能保证已达到流的"终点"。特别是,如果传输中有任何暂停,或者发件人比阅读器慢,则DataAvailable可以为false。