我有一个使用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();
}
这似乎总是在所有数据到达之前退出读取循环。我做错了什么?
答案 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。