我正在尝试使用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页面没有提及任何大小限制。
答案 0 :(得分:3)
并不是说它有任何人为限制,这是你尝试做的Streaming
性质的副产品。我觉得以下一行是罪犯:
responseStream.Read(responseBytes, 0, (int)response.ContentLength);
我过去曾遇到过这个问题(使用TCP流),但它并没有读取数组的所有内容,因为它们还没有通过网络发送过。我会尝试这样做。
for (int i = 0; i < response.ContentLength; i++)
{
responseBytes[i] = responseStream.ReadByte();
}
这样,它将确保一直读到流的结尾。
修改强>
基于BinaryReader
的{{1}}解决方案效率更高。以下是相关解决方案:
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();
}
答案 1 :(得分:2)
您假设Read
正在读取您请求的字节数。但请求的数量只是一个上限。你必须容忍阅读小块。
您可以使用var bytes = new BinaryReader(myStream).ReadBytes(count);
来读取确切的数字。不要经常调用ReadByte
,因为这会占用大量CPU资源。
最好的解决方案是退出相当手动的HttpWebRequest
并使用HttpClient
或WebClient
。所有这些都是自动化的,您可以获得byte[]
。