【问题标题】:C# - Is there a limit to the size of an httpWebRequest stream?C# - httpWebRequest 流的大小是否有限制?
【发布时间】:2016-11-15 00:58:00
【问题描述】:

我正在尝试构建一个应用程序,该应用程序使用 httpwebrequests 从自定义网络服务器下载一个小的二进制文件 (20-25 KB)。

这是服务器端代码:

Stream UpdateRequest = context.Request.InputStream;
byte[] UpdateContent = new byte[context.Request.ContentLength64];
UpdateRequest.Read(UpdateContent, 0, UpdateContent.Length);
String remoteVersion = "";
for (int i = 0;i < UpdateContent.Length;i++) { //check if update is necessary
    remoteVersion += (char)UpdateContent[i];
}

byte[] UpdateRequestResponse;

if (remoteVersion == remotePluginVersion) {
    UpdateRequestResponse = new byte[1];
    UpdateRequestResponse[0] = 0; //respond with a single byte set to 0 if no update is required
} else {
    FileInfo info = new FileInfo(Path.Combine(Directory.GetCurrentDirectory(), "remote logs", "PointAwarder.dll"));
    UpdateRequestResponse = File.ReadAllBytes(Path.Combine(Directory.GetCurrentDirectory(), "remote logs", "PointAwarder.dll"));
    //respond with the updated file otherwise
}

//this byte is past the threshold and will not be the same in the version the client recieves
Console.WriteLine("5000th byte: " + UpdateRequestResponse[5000]);

//send the response
context.Response.ContentLength64 = UpdateRequestResponse.Length;
context.Response.OutputStream.Write(UpdateRequestResponse, 0, UpdateRequestResponse.Length);
context.Response.Close();

在此之后,数组 UpdateRequestResponse 包含整个文件并已发送到客户端。

客户端运行这段代码:

//create the request
WebRequest request = WebRequest.Create(url + "pluginUpdate");
request.Method = "POST";
//create a byte array of the current version
byte[] requestContentTemp = version.ToByteArray();
int count = 0;
for (int i = 0; i < requestContentTemp.Length; i++) {
    if (requestContentTemp[i] != 0) {
        count++;
    }
}
byte[] requestContent = new byte[count];
for (int i = 0, j = 0; i < requestContentTemp.Length; i++) {
    if (requestContentTemp[i] != 0) {
        requestContent[j] = requestContentTemp[i];
        j++;
    }
}

//send the current version
request.ContentLength = requestContent.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(requestContent, 0, requestContent.Length);
dataStream.Close();

//get and read the response
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
byte[] responseBytes = new byte[response.ContentLength];
responseStream.Read(responseBytes, 0, (int)response.ContentLength);
responseStream.Close();
response.Close();

//if the response containd a single 0 we are up-to-date, otherwise write the content of the response to file
if (responseBytes[0] != 0 || response.ContentLength > 1) {
    BinaryWriter writer = new BinaryWriter(File.Open(Path.Combine(Directory.GetCurrentDirectory(), "ServerPlugins", "PointAwarder.dll"), FileMode.Create));
    writer.BaseStream.Write(responseBytes, 0, responseBytes.Length);
    writer.Close();
    TShockAPI.Commands.HandleCommand(TSPlayer.Server, "/reload");
}

客户端上的字节数组 responseBytes 应该与服务器上的数组 UpdateRequestResponse 相同,但事实并非如此。在大约 4000 字节之后,之后的每个字节都设置为 0,而不是它应该是什么(responseBytes[3985] 是最后一个非零字节)。

这是因为 httpWebRequest 有大小限制吗?我在我的代码中看不到任何可能导致它的错误,并且相同的代码在我只需要传递短数据序列(小于 100 字节)的其他情况下也有效。

MSDN 页面没有提到任何这样的大小限制。

【问题讨论】:

    标签: c# .net http httpwebrequest httpwebresponse


    【解决方案1】:

    这并不是说它有任何人为限制,这是您尝试做的Streaming 性质的副产品。我感觉下面这行是违规者:

    responseStream.Read(responseBytes, 0, (int)response.ContentLength);
    

    我过去遇到过这个问题(使用 TCP 流),它不会读取数组的所有内容,因为它们还没有全部通过网络发送。这就是我要尝试的方法。

    for (int i = 0; i < response.ContentLength; i++)
    {
       responseBytes[i] = responseStream.ReadByte();
    }
    

    这样,它将确保一直读取到流结束。

    编辑

    usr 的基于BinaryReader 的解决方案效率更高。这是相关的解决方案:

    BinaryReader binReader = new BinaryReader(responseStream);
    const int bufferSize = 4096;
    byte[] responseBytes;
    using (MemoryStream ms = new MemoryStream())
    {
        byte[] buffer = new byte[bufferSize];
        int count;
        while ((count = binReader.Read(buffer, 0, buffer.Length)) != 0)
            ms.Write(buffer, 0, count);
        responseBytes = ms.ToArray();
    }
    

    【讨论】:

    • 这似乎已经解决了!非常感谢,我永远不会猜到;我认为在所有数据完全传输之前暂停执行。既然这是我的第一个问题,那么您有没有看到我下次可以改进的地方?
    • 这是一个棘手的问题,我实际上将代码推送到生产环境中运行良好(本地!),然后在现场测试中开始失败,因为我没有考虑到这个问题。这个问题写得很好,所以很遗憾我没有任何建议给你!
    • 这听起来像是一场噩梦!在我的情况下,我根本无法在本地进行测试,我必须在实时服务器上创建应用程序的第二个实例(使用修改后的端口/管道名称等)。你认为我的问题写得很好是不幸的吗?这让我觉得很奇怪......不过还是谢谢你的赞美。
    • 很遗憾我没有任何建设性的批评可以给你:)。我为您可能想要研究的答案添加了一个更好的解决方案,解决了 usr 提到的关于 ReadByte() 循环的高 CPU 使用率的问题。
    【解决方案2】:

    您假设Read 正在读取您请求的字节数。但是请求的计数只是一个上限。你必须容忍阅读小块。

    您可以使用var bytes = new BinaryReader(myStream).ReadBytes(count); 读取确切的数字。不要太频繁地调用ReadByte,因为这会占用大量 CPU。

    最好的解决方案是放弃相当手动的HttpWebRequest 并使用HttpClientWebClient。所有这些都是为您自动完成的,您会收到 byte[]

    【讨论】:

    猜你喜欢
    • 2011-07-30
    • 2021-12-10
    • 1970-01-01
    • 2022-10-23
    • 2018-06-24
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 2013-12-13
    相关资源
    最近更新 更多