C++: HTTP Download
FMFlash 06.06.2003 - 10:56 1248 10
FMFlash
tranceCoder
|
ich hab schon seit einiger zeit eine eigene klasse für http-downloads in verwendung. das problem dabei ist das es extrem cpu-belastend ist (bei ~120kB/s ca 20% auslastung @ >2ghz axp) da ich die sehr ineffiziente buffergröße von 1 byte verwende (recv (socket, buffer, 1, 0)). doch nur mit dieser war es mir möglich auch binäre dateien wie bilder, exe, zip usw fehlerfrei zu übertragen.
dann hab ich die übertragung etwas verbessert indem ich je 100kbyte eingelesen hab, und dann erst die daten in den übergebenen buffer bzw die datei zu schreiben - jedoch ist dann das problem mit den nicht-text-dateien wieder aufgetreten.
ich bin mit meiner weisheit leider am ende und kann nur noch raten und herumprobieren, aber ich hoffe hier gibt es leute mit mehr erfahrung in dem bereich.
die letzte änderung mit dem buffer bringt mich allerdings auf den gedanken das das problem weniger beim empfang als beim weiterverarbeiten der daten liegt.
tia
|
atrox
in fairy dust... I trust!
|
einer der häufigsten fehler in so einem zusammenhang, ist das richtige zusammensetzen der datenblöck, entweder zwischendurch oder am schluß.
hast du zb bedacht, daß recv überhaupt nicht verpflichtet ist, dir den gesamten buffer vollzuschreiben, sondern dir im rückgabewert sagt, wieviel bytes es wirklich sind ?
weiters, könntest du ja mit speziell präparierten testdaten untersuchen, was für eine art von korruption stattfindet - da läßt womöglich rückschlüsse zu.
|
FMFlash
tranceCoder
|
einer der häufigsten fehler in so einem zusammenhang, ist das richtige zusammensetzen der datenblöck, entweder zwischendurch oder am schluß.
hast du zb bedacht, daß recv überhaupt nicht verpflichtet ist, dir den gesamten buffer vollzuschreiben, sondern dir im rückgabewert sagt, wieviel bytes es wirklich sind ? selbstverständlich, auf ein char *pch = downloadSocket.recvData(); folgt zur feststellung der erhaltenen länge etwas wie int len = downloadSocket.getReceivedLength(); wenn len == 0 beende ich den transfer, da offensichtlich keine daten mehr geschickt werden. frage: der einsatz eines char[] als receive-buffer ist auch bei binären dateien legitim? sollte es allerdings imho sein, da recv selbst einen char FAR* buffer verwendet weiters, könntest du ja mit speziell präparierten testdaten untersuchen, was für eine art von korruption stattfindet - da läßt womöglich rückschlüsse zu. gute idee, nur wie sollte so eine testdatei denn aussehen?
|
atrox
in fairy dust... I trust!
|
ab dem charachter 32 sind alle darstellbar, von jedem würde ich 64 oder 128 hintereinander schreiben
im hex-editor müsste sich dann sehr leicht unstimmigkeiten finden lassen, weil für gewöhnlich 16 bytes in einer zeile angezeigt werden.
für blocksize verwende irgendeine "krumme" größe zb eine primzahl.
|
FMFlash
tranceCoder
|
soweit, so gut jetzt hab ich es so gelöst: ich statte recv() mit einem angemesseneren buffer von 1460 byte aus und verarbeite dann die empfangenen daten byte für byte. das hält die cpu-belastung bei 0-2% und gewährleistet eine korrekte darstellung der daten. ABER, irgend etwas scheine ich verbaut zu haben, da das testprogramm beim aufruf von PostQuitMessage(0) einen hübschen fehler produziert der mich etwas stutzig macht:
"Die Anweisung in "0x5501f104" verweist auf Speicher in "0x5501f104". Der Vorgang "read" konnte nicht auf dem Speicher durchgeführt werden."
was könnte diesen fehler verursachen?
|
that
Hoffnungsloser Optimist
|
Was machst du byteweise mit den empfangenen Daten?
Zu dem Fehler: Sieht so aus, als würde eine DLL angesprungen, die nicht mehr im Speicher ist. Hast du vergessen, irgendeinen Hook oder sowas freizugeben?
|
FMFlash
tranceCoder
|
Was machst du byteweise mit den empfangenen Daten? das verdeutlicht wohl am besten etwas code: zum verständnis meiner etwas willkürlichen namensgebung:
... [int] len = empfangene bytes
... [char*] ch = buffer für empfangene daten
... [char] recvBuffer = zwischenablage für das bearbeitete byte
... [string] _x = hierin werden die daten zusammengesetzt; wird im
weiteren zum schreiben auf die platte bzw speicherung im speicher benutzt
for (int a=0; a<len; ++a)
{
if (ch[a] != 0)
recvBuffer = ch[a];
else
recvBuffer = '\0';
_x += recvBuffer;
}
das ist jedenfalls meine methode um jegliche formatierung durch direkte zuweisungen wie _x = ch zu vermeiden, für verbesserungsschläge bin ich offen. Zu dem Fehler: Sieht so aus, als würde eine DLL angesprungen, die nicht mehr im Speicher ist. Hast du vergessen, irgendeinen Hook oder sowas freizugeben? hmmm den fehler hab ich sicher mit dieser veränderung erst eingebracht - hooks verwend ich keine.
Bearbeitet von FMFlash am 06.06.2003, 20:36
|
FMFlash
tranceCoder
|
![:D](/images/smilies/biggrin.gif) hab den fehler entdeckt! folgendes war passiert: beim herstellen der TCP-verbindung über den socket lege ich die größe des empfangsbuffers fest, und reserviere dementsprechend speicher: buffer = (char*) malloc (bufferSize); so, nun downloade ich den http header mit einem buffer von 1 byte da sich so das ende des headers wesentlich unkomplizierter findet und bei den wenigen 100B die performance zu vernachlässigen ist. vor dem beginn des eigentlichen downloads erhöhe ich die buffergröße - dabei hab ich allerdings vergessen ein buffer = (char*) realloc (buffer, new_size); zu machen ![:rolleyes:](/images/smilies/rolleyes.gif) und somit war recv() zum abschuss freigegeben. diesen fehler hab ich jetzt behoben und siehe da; schnell und zuverlässig
|
FMFlash
tranceCoder
|
ein problem hab ich jetzt allerdings noch: wie breche ich einen laufenden download - zb wenn das programm beendet wird - sicher wieder ab? derzeit tritt dann beim beenden der gleiche fehler auf wie zuvor
|
atrox
in fairy dust... I trust!
|
du mußt einfach nur den socket schließen, und 'sicher' (also ohne dir pointer zusammenzuhauen, bzw auf ungültige daten zuzugreifen) aus der schleife aussteigen.
|
FMFlash
tranceCoder
|
done. wunderbar solved *stempel*
|