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?


  • Mod

    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...


  • Mod

    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? 😃


  • Mod

    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.


Anmelden zum Antworten