Windows downloader läd nicht viel



  • Hallo,
    ich habe basierend auf einem Tutorial einen kleinen downloader geschrieben, welcher cURL aus dem Netz downloaden soll. Das Programm scheint die ganze Datei herunter zu laden, allerdings wird diese nicht wie geplant gespeichert. Folgend der Code. Ich würde mich freuen, wenn jemand von euch Zeit findet, sich das Programm mal anzuschauen und evlt neben dem eigentlichen Problem auch Design-technische tipps zu geben:

    /*
    Programm to download cURL and istall it on a windows machine
    */
    
    #include <iostream>
    #include <fstream>
    #include <errno.h>
    #include <string>
    #include <stdio.h>
    
    #include <windows.h>
    #include <winsock2.h>
    #include <io.h>
    
    const int HTTP_PORT = 80;
    const char SERVER[] = "www.mirrorspace.org";
    const char FILENAME[]   = "/curl/curl-7.15.3-win32-ssl-sspi.zip";
    const char SAVE[]   = "C:\\Temp\\curl.zip";
    
    int main(int argc, char **argv)
    {
        struct hostent *hostinfo;
        char command[1024];
        char buf[1024];
    
        //create winsock
        WSADATA wsaData;
        if(WSAStartup (MAKEWORD(1, 1), &wsaData) != 0) {
                      fprintf (stderr, "WSAStartup(): can not initalize winsock.\n");
                      exit (EXIT_FAILURE);
        }
    
        /* create socket */
        int sock = socket (AF_INET, SOCK_STREAM, 0);
        if (sock == -1) {
           perror ("socket()");
           exit (EXIT_FAILURE);
        }
    
        /* commit server address */
        struct sockaddr_in host_addr;
        memset( &host_addr, 0, sizeof (host_addr));
        host_addr.sin_family = AF_INET;
        host_addr.sin_port = htons (HTTP_PORT);
        host_addr.sin_addr.s_addr = inet_addr (SERVER);
        if (host_addr.sin_addr.s_addr == INADDR_NONE) {
           /* Server was not given by IP but by name */
           hostinfo = gethostbyname (SERVER);
           if (hostinfo == NULL) {
              perror ("gethostbyname()");
              exit (EXIT_FAILURE);
           }
           memcpy((char*) &host_addr.sin_addr.s_addr, hostinfo->h_addr, hostinfo->h_length);
        }
    
        /* create connection */
        if (connect(sock, (struct sockaddr *) &host_addr, sizeof(struct sockaddr)) == -1) {
           perror ("connect()");
           exit (EXIT_FAILURE);
        }
    
        /* create HTTP-GET-command */
        sprintf (command, "GET %s HTTP/1.0\nHost: %s\n\n", FILENAME, SERVER);
    
        printf("starting download\n");
    
        /* send command */
        unsigned int bytes_sent;
        bytes_sent = send (sock, command, strlen (command), 0);
        if (bytes_sent == -1) {
            perror ("send()");
            exit (EXIT_FAILURE);
        }
    
        // receive answer of the server */
        unsigned int bytes_recv;
        while ((bytes_recv = recv (sock, buf, sizeof(buf), 0)) > 0) {
             {
                           std::ofstream file(SAVE);
                           file<<bytes_recv;
             }
        }
        if (bytes_recv == -1) {
           perror ("recv()");
           exit (EXIT_FAILURE);
        }
    
        printf ("\n");
    
        closesocket(sock);
        WSACleanup();
    
        system("PAUSE");
        return 0;
    }
    


  • Entscheide dich mal ob du C oder C++ benutzen willst 😉

    Deine while Schleife ist falsch. Du schreibst doch überhaupt nicht die empfangenen Daten in die Datei. Ausserdem schickt der HTTP Server ja erst noch einen HTTP Header zurück, den du erst noch parsen musst, bevor die eigentlichen Daten kommen.

    Wenn du für Windows programmierst, kannst du auch gleich die WinInet Funktionen benutzen, dann ersparst du dir diese Arbeit: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wininet/wininet/wininet_reference.asp



  • Ich möchte den code ja gerade portabel halten, da ich evtl später so ein ähnliches Programm für linux schreiben möchte. Ich habe den code jetzt ein bisschen verändert, sodass er in die datei schreibt und den anfang parst. Das in die datei schreiben hat super geklappt, aber der Parser will einfach nicht. Das Programm startet aber es wird nichts mehr in die datei geschrieben. Anbei der veränderte code. Ich hoffe jemand sieht den Fehler darin:

    // receive answer of the server */
        unsigned int bytes_recv;
        std::ofstream file(SAVE);
        char headerEnd[] = "Content-Type: application/zip\n";
        char *pHE = headerEnd;
        int c = 0;
        bool HeaderReceived = false;
        while ((bytes_recv = recv (sock, buf, sizeof(buf), 0)) > 0) {
             {
             if(HeaderReceived) {
                           file<<buf;
             } else {
                           //parse for response header
                           char *bufPointer = buf;
                           while(true) {
                           if(*bufPointer == *pHE) {
                                          pHE++;
                                          bufPointer++;
                                          c++;
                                          if(c == sizeof(headerEnd)) {
                                               HeaderReceived = true;
                                               break;
                                          }
                           } else { 
                             pHE = headerEnd;
                             c = 0;
                           }
                           }
                           }
             }
        }
    


  • ich würde die antwort in zeilen unterteilen. wenn eine leere zeile kommt ist der header vollständig und ab da schreibst du in die datei.



  • Übrigens würde ich zum Schreiben lieber fstream::write() verwenden als op<< (op<< erwartet einen nullterminierten C-String als Eingabe - und das trifft ziemlich sicher nicht auf deinen Zwischenpuffer zu).



  • ok, ich hab das mal versucht umzusetzten, aber nach wie vor legt er die datei an aber schreibt nix hinein. Ich hoffe mal, du weist was ich falsch gemacht habe:

    bool HeaderReceived = false;
        std::fstream fStream;
        fStream.open(SAVE,std::fstream::binary);
        char *bufPointer = buf;
        while ((bytes_recv = recv (sock, buf, sizeof(buf), 0)) > 0)
        {
             if(HeaderReceived) {
                           fStream.write(buf,sizeof(buf));
             } else {
                           //parse for response header (new line = end of header)
                           while(true) {
                           if(*bufPointer == '\n' && 
                           *(bufPointer-1) == '\n') 
                           {
                                          HeaderReceived = true;
                                          fStream.write(bufPointer,sizeof(bufPointer));
                                          break;
                           } else 
                           { 
                                  bufPointer++;
                           }
                           }
             }
        }
    


  • Versuch's mal, wenn du den Stream per "fStream.open(SAVE,std::ios::out|std::ios::binary);" öffnest (sprich: Du solltest ihm dazusagen, daß er den Stream zur Ausgabe öffnen soll).

    PS: Und "fStream.write(buf,bytes_recv);" dürfte auch von Vorteil sein 😉

    PPS: "sizeof(bufPointer)" ist vermutlich auch zu klein, um die Größe des ersten Blocks (abzüglich Header) zu beschreiben - da brauchst du "bytes_recv - (bufPointer-buf)".



  • Hmm, das laden hat begonnen, aber die datei ließ sich nicht öffnen. Darum habe ich mir die eigentliche Datei per Browser heruntergelade und geschaut, um wieviel byte sie sich verändert. Jetzt habe ich:

    fstream fStream;
        fStream.open(SAVE,ios::out | ios::binary);
        char *bufPointer = buf;
        while ((bytes_recv = recv (sock, buf, sizeof(buf), 0)) > 0)
        {
             if(HeaderReceived) {
                           fStream.write(buf,bytes_recv);
             } else {
                           //parse for response header (new line = end of header)
                           while(true) {
                           if(*bufPointer == '\n' && 
                           *(bufPointer-1) == '\n') 
                           {
                                          HeaderReceived = true;
                                          cout<<"bytes_recv: "<<bytes_recv<<"\n - "<<(bufPointer-buf)<<endl;
                                          fStream.write(bufPointer,bytes_recv - (bufPointer-buf) + 156);
                                          break;
                           } else 
                           { 
                                  bufPointer++;
                           }
                           }
             }
        }
    

    Hat jemand ne Ahnung, warum das 156 zuviel sind?

    Und noch eine Andere Frage zum öffnen des FileStreams:
    Was ist der unterschied zwischen ios::out und fstream::out? Klar, anderer namespace aber wieso funktioniert ios::out überhaupt?

    Danke 😃


Anmelden zum Antworten