2016-07-12 4 views
2

Ich versuche eine Anwendung zu erstellen, die eine kleine Binärdatei (20-25 KB) von einem benutzerdefinierten Webserver mit httpwebrequests herunterlädt.C# - Gibt es eine Grenze für die Größe eines httpWebRequest-Streams?

Dies ist die serverseitige Code:

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

Danach wird der Array UpdateRequestResponse die gesamte Datei enthält und an den Client gesendet wurde.

Der Client läuft diesen Code:

//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"); 
} 

Das Byte-Array responseBytes auf dem Client sollte auf dem Array UpdateRequestResponse auf dem Server identisch sein, aber es ist nicht. nach etwa 4000 Bytes wird jedes Byte danach auf 0 gesetzt, anstatt wie es sein sollte (responseBytes [3985] ist das letzte Nicht-Null-Byte).

Ist dies der Fall, weil httpWebRequest eine Größenbeschränkung hat? Ich kann keinen Fehler in meinem Code sehen, der sie verursachen könnte, und derselbe Code funktioniert in anderen Fällen, in denen ich nur kurze Datensequenzen (weniger als 100 Bytes) weitergeben muss.

Die MSDN-Seiten erwähnen keine Größenbeschränkung wie folgt.

Antwort

2

Es ist nicht, dass es eine künstliche Grenze hat, dies ist ein Nebenprodukt der Streaming Art von dem, was Sie versuchen zu tun. Ich habe das Gefühl, die folgende Zeile der Täter:

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

ich dieses Problem in der Vergangenheit gehabt haben (mit TCP-Streams), ist es nicht der gesamte Inhalt des Arrays zu lesen, weil sie haven‘ Alle wurden schon über den Draht gesendet. Das würde ich stattdessen versuchen.

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

Auf diese Weise wird es sicherstellen, den ganzen Weg bis zum Ende des Streams zu lesen.

EDIT

des usr BinaryReader basierte Lösung ist viel effizienter. Hier ist die relevante Lösung:

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

Das scheint es behoben zu haben! Vielen Dank, das hätte ich nie erraten. Ich dachte, dass die Ausführung angehalten wurde, bis alle Daten vollständig übertragen wurden. Da dies meine erste Frage ist, gibt es irgendetwas, das Sie gesehen haben, dass ich das nächste Mal verbessern könnte? – Annonymus

+0

Es ist ein kniffliges Problem, ich habe Code in die Produktion gedrängt, der gut funktioniert (lokal!) Und dann im Live-Test versagt, weil ich dieses Problem nicht berücksichtigt habe. Die Frage war sehr gut geschrieben, deshalb habe ich leider keinen Rat für dich! –

+0

Das klingt wie ein Albtraum! In meinem Fall kann ich gar nicht lokal testen, ich muss eine zweite Instanz der Anwendung auf dem Live-Server erstellen (mit geänderten Ports/Pipe-Namen etc.). Sie denken, es ist bedauerlich, dass meine Frage gut geschrieben wurde? Das kommt mir seltsam vor ... Danke für das Kompliment. – Annonymus

2

Sie davon aus, dass Read liest so viele Bytes wie Sie verlangen. Aber die angeforderte Anzahl ist nur eine obere Grenze. Sie müssen tolerieren, kleine Stücke zu lesen.

Sie können var bytes = new BinaryReader(myStream).ReadBytes(count); verwenden, um eine genaue Zahl zu lesen. Rufen Sie nicht zu oft ReadByte, weil das sehr CPU-intensiv ist.

Die beste Lösung wäre, von der ziemlich manuellen HttpWebRequest wegzugehen und HttpClient oder WebClient zu verwenden. All dies ist für Sie automatisiert und Sie erhalten eine byte[] zurück.

+0

Gute Anmerkung. Ich habe meine Antwort geändert, um das zu reflektieren. Unglücklicherweise wird der 'ReadBytes()' Aufruf eine 'OutOfMemoryException' auf 32-Bit Systemen werfen (http://stackoverflow.com/questions/8613187/an-elegant-way-to-consume-all-bytes-of- a-binaryreader), wenn 'contentLength' groß genug ist. Ich habe meine Antwort mit Ihrer Methode und der Problemumgehung aktualisiert. –

+0

Es gibt keine Möglichkeit, ein längeres Array zu erstellen. MemStream und Byte [] können es auch nicht tun. – usr

Verwandte Themen