"Christmas - the time to fix the computers of your loved ones" « Lord Wyrm

C++: HTTP Download

FMFlash 06.06.2003 - 10:56 1202 10
Posts

FMFlash

tranceCoder
Avatar
Registered: Mar 2001
Location: Wien
Posts: 2037
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!
Avatar
Registered: Sep 2002
Location: HTTP/1.1 404
Posts: 2782
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
Avatar
Registered: Mar 2001
Location: Wien
Posts: 2037
Zitat von atrox
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

Zitat von atrox
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!
Avatar
Registered: Sep 2002
Location: HTTP/1.1 404
Posts: 2782
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
Avatar
Registered: Mar 2001
Location: Wien
Posts: 2037
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

Moderator
Hoffnungsloser Optimist
Avatar
Registered: Mar 2000
Location: MeidLing
Posts: 11326
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
Avatar
Registered: Mar 2001
Location: Wien
Posts: 2037
Zitat von that
Was machst du byteweise mit den empfangenen Daten?

das verdeutlicht wohl am besten etwas code:

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.

Zitat von that
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
Avatar
Registered: Mar 2001
Location: Wien
Posts: 2037
:D 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: und somit war recv() zum abschuss freigegeben.

diesen fehler hab ich jetzt behoben und siehe da; schnell und zuverlässig ;)

FMFlash

tranceCoder
Avatar
Registered: Mar 2001
Location: Wien
Posts: 2037
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!
Avatar
Registered: Sep 2002
Location: HTTP/1.1 404
Posts: 2782
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
Avatar
Registered: Mar 2001
Location: Wien
Posts: 2037
done. wunderbar :cool:
solved *stempel*
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz