Problem mit speichern von Binärdatei und vermutlich Nullbyteterminierung
-
Hallo,
zurzeit versuche ich mit Sockets ein Binary File (ein Bild) herunterzuladen. Das funktioniert, jedoch wird es nicht richtig abgespeichert..
Zuerst der Code:
#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> #include <iostream> #include <string.h> #include <fstream> using namespace std; int main(void) { int s = socket(AF_INET, SOCK_STREAM, 0); struct hostent *host = gethostbyname("www.google.de"); struct sockaddr_in addr; addr.sin_addr = *(struct in_addr *)host->h_addr; addr.sin_port = htons(80); addr.sin_family = AF_INET; connect(s, (sockaddr *)&addr, sizeof(addr)); string rrr = "GET /intl/de_de/images/logo.gif HTTP/1.1\r\nHost: www.google.de\r\nConnection: close\r\n\r\n"; send(s, rrr.c_str(), rrr.size(), 0); char recieved[1024]; memset(recieved, 0, sizeof(recieved));fstream f1("logo.gif", ios::out | ios::binary); while(recv(s, recieved, sizeof(recieved )-1, 0)) { f1 << recieved; memset(recieved, 0, sizeof(recieved)); } f1.close(); }Ja, die HTTP-Response headers werden mit in die Datei geschrieben, aber das ist ein Problem, welches nicht besprochen werden muss da die Lösung mir geläufig ist

Das Problem ist scheinbar die Nullbyte-Terminierung. Öffne ich das "richtig heruntergeladene" Logo der Suchmaschine mit einem Hexeditor, so erhalte ich:47 49 46 38 39 61 2d 01 6e 00 e7
Die Version meines Programms:
47 49 46 38 39 61 2d 01 6e 82 5a 69 0e...
Hier ist das Nullbyte laut meiner Vermutung das Problem.Ich glaube, ich sollte Memory-Funktionen verwenden,
statt String-Funktionen um diese entsprechen zu behandeln. Weiss jemand genau, wie man das Bild richtig abspeichert?
-
Warum benutzt du dann cstrings, wenn die Nullterminierung Probleme macht? Offensichtlich ist dir std::string ja bekannt, auch wenn ich mich ein wenig wundere, dass dein Programm überhaupt kompiliert. string.h sollte nämlich eigentlich die C Stringfunktionen enthalten (also das was in C++ in cstring steht) und nicht std::string.
-
Nunja, versuch mal recv auf std::string zu machen...
-
Ok, recv kannte ich jetzt nicht, da Windowskram.
Dann ist eine einfache Lösung, die Ausgabe byteweise zu machen.
-
Ich habe das Gefühl, du weisst nicht, von was du sprichst. recv ist keineswegs Windows-Kram.
#include <sys/types.h>
#include <sys/socket.h>Und ich glaube, Windows Compiler würden unter anderem diese Headerdateien nicht finden ;).
Dann ist eine einfache Lösung, die Ausgabe byteweise zu machen.
und wie?

-
YetAnotherProblem-haber schrieb:
Ich habe das Gefühl, du weisst nicht, von was du sprichst. recv ist keineswegs Windows-Kram.
War der Top Treffer bei ggogle für recv. Aber ist für das Problem ja auch völlig egal.
und wie?

for (int i=0; i<1024;++i) f1.put(recieved[i]);edit: Oder auch mit write(), ist wahrscheinlich sogar besser.
edit2: Ja, ist besser:
f1.write(recieved,1024);
-
Es sollte aber nur soviel geschrieben werden, wie auch mit recv() empfangen wird, d.h. den Rückgabewert beachten!!!
-
Genau, Rückgabewert von recv nicht beachtet, klassischer Fehler.
Nur mal als Denkanstoß: Du gehst wohl nicht davon aus, dass jedes Bild bei Google exakt 1024 Bytes lang ist. Dir ist zudem bereits bewusst, dass Nullbytes C-Strings terminieren. Eine Länge speicherst Du auch nirgends.
Ja, wie soll denn der operator<< nun überhaupt feststellen können, wie lang die Daten sind?
-
Danke, ich werde mich dann mal damit beschäftigen.