Http & Socket Problem...



  • Hey Leute 😉
    bin recht neu in der c++ Welt (ne knappe woche aktiv), naja die grundlagen kann ich aber eigentlich (oop und klassen & syntax etc)
    wollte mich ma an die netztwerk programmierung ranmachen und hab mir gedacht ich mach das einefach mal in verbindung mit http 😉
    nun habe ich die folgende klasse...

    #include <iostream>
    #include "Http.h"
    #include <windows.h>
    #include <winsock2.h>
    #include <stdio.h>
    #include <sstream>
    #include <cstring>
    #include <string>
    #include <fstream>
    
    using namespace std;
    
    Http::Http()//Constructor
    {
        Port = 80;
        SendPacket(FormPacket("www.google.de"));
    }
    
    Http::~Http()//Destructor
    {
        //dtor
    }
    
    string Http::SendPacket(string Packet)
    {
        WSADATA wsa;
        long rc = WSAStartup(MAKEWORD(2,2),&wsa);
    
        if(rc != 0)
            cout << "Fehler beim starten von WSA. Fehler: " << rc << endl;
        else
            cout << "WSA erfolgreich gestartet" << endl;
    
        SOCKET sock;
        sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(sock == INVALID_SOCKET)
            cout << "Fehler beim erstellen des Sockets. Fehler: " << WSAGetLastError() << endl;
        else
            cout << "Socket erfolgreich erstellt" << endl;
    
        SOCKADDR_IN addr;
    
        memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten
        addr.sin_family=AF_INET;
        addr.sin_port=htons(Port); //Port setzen
    
        rc = HostAufLoesen(const_cast<char *>(Host.c_str()),&addr);
    
        if(rc == SOCKET_ERROR)
            cout << "Ip konnte nicht aufgeloest werden" << endl;
        else
            cout << "Ip erfolgreich aufgeloest" << endl;
    
        rc=connect(sock,(SOCKADDR*)&addr,sizeof(SOCKADDR));
    
        if(rc==SOCKET_ERROR)
            cout << "Fehler beim verbinden. Fehler: " << WSAGetLastError() << endl;
        else
            cout << "Verbindung mit " << Host << " wurde erfolgreich aufgebaut" << endl;
    
        SendAll(sock,Packet.c_str(),Packet.length());
    
        stringstream out;
        out << Packet.length();
        cout << "LAENGE!!:::" << out.str();
    
    //    if(rc == SOCKET_ERROR)
    //        cout << "Fehler beim senden des Packetes. Fehler: " << WSAGetLastError() << endl;
    //    else
    //        cout << "Packet erfolgreich gesendet" << endl;
    
        char buf2[123456];
        rc = recv(sock, buf2,123456,0);
    
        if(rc == SOCKET_ERROR)
            cout << "Fehler beim empfangen der Antwort. Fehler: " << WSAGetLastError() << endl;
        else
            cout << "Antwort erfolgreich empfangen:" << endl;
    
        closesocket(sock);
        WSACleanup();
    
        cout << buf2 << endl;
    
        ofstream myfile;
        myfile.open ("example.html");
        if(!myfile.is_open())
            cout << "\nFail!!!!!\n" << endl;
        myfile << Packet;
        myfile.close();
    
        cout << "PENIS!";
    
        return "";
    }
    
    void Http::SendAll(int socket, const char* const buf, const int size)
    {
        int bytesSent = 0; // Anzahl Bytes die wir bereits vom Buffer gesendet haben
        do
        {
            bytesSent += send(socket, buf + bytesSent, size - bytesSent, 0);
        } while(bytesSent < size);
    }
    
    long Http::HostAufLoesen(char* hostnameOrIp, SOCKADDR_IN* addr)
    {
        long rc;
        unsigned long ip;
        HOSTENT* he;
        /* Parameter prüfen */
    
        if(hostnameOrIp==NULL || addr==NULL)
            return SOCKET_ERROR;
        /* eine IP in hostnameOrIp ? */
    
        ip=inet_addr(hostnameOrIp);
    
        /* bei einem fehler liefert inet_addr den Rückgabewert INADDR_NONE */
    
        if(ip!=INADDR_NONE)
        {
            addr->sin_addr.s_addr=ip;
            return 0;
        }
        else
        {
            /* Hostname in hostnameOrIp auflösen */
            he=gethostbyname(hostnameOrIp);
            if(he==NULL)
            {
            return SOCKET_ERROR;
            }
        else
        {
            /*die 4 Bytes der IP von he nach addr kopieren */
            memcpy(&(addr->sin_addr),he->h_addr_list[0],4);
        }
        return 0;
        }
    }
    
    string Http::FormPacket(string sUrl, string sPost, string sType) //Create the Packetstring
    {
        if(sPost == "")
            PacketToSend += "GET " + GetSubPage(sUrl) +" HTTP 1.1\r\n";
        else
            PacketToSend += "POST " + GetSubPage(sUrl) +" HTTP 1.1\r\n";
    
        PacketToSend += "Host: " + GetSubHost(sUrl) + "\r\n";
    
        if(UserAgent == "")
            PacketToSend += "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729)\r\n";
        else
            PacketToSend += "User-Agent: " + UserAgent + "\r\n";
    
        PacketToSend += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
        PacketToSend += "Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
        PacketToSend += "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n";
        PacketToSend += "Keep-Alive: 115\r\n";
        PacketToSend += "Connection: keep-alive\r\n";
    
        if(Cookies != "")
            PacketToSend += "Cookie: " + Cookies + "\r\n";
    
        if(Referer != "")
            PacketToSend += "Referer: " + Referer + "\r\n";
    
        if(sPost != "")
        {
            PacketToSend += "Content-Type: " + sType + "\r\n";
            PacketToSend += "Content-Length: ";
            stringstream out;
            out << sPost.length();
            PacketToSend.append(out.str());
            PacketToSend += "\r\n\r\n";
            PacketToSend += sPost;
        }
        else
        {
            PacketToSend += "\r\n";
        }
    
        cout << "Packet:\r\n\r\n" << PacketToSend << endl;
    
        return PacketToSend;
    }
    
    string Http::GetSubPage(string sUrl) // Example: 'http://google.de/index.php' -> '/index.php'
    {
        string tUrl;
        string Page;
        if(sUrl[0] == 'h' && sUrl[1] == 't' && sUrl[2] == 't' && sUrl[3] == 'p' && sUrl[4] == ':' && sUrl[5] == '/' && sUrl[6] == '/') // Check if starts with 'http://'
        {
            for(unsigned int c = 7; c < sUrl.size(); c++)
            {
                tUrl += sUrl[c];
            }
        }
        else
        {
            tUrl = sUrl;
        }
    
        for(unsigned int c = 0; c < tUrl.size(); c++)
        {
            if(tUrl[c] == '/')
            {
                for(unsigned int c2 = c; c2 < tUrl.size(); c2++)
                {
                    Page += tUrl[c2];
                }
                break;
            }
        }
    
        if(Page == "")
            Page += "/";
    
        return Page;
    }
    
    string Http::GetSubHost(string sUrl) // Example: 'http://google.de/index.php' -> 'google.de'
    {
        string tUrl;
        string bUrl;
        string Host;
        if(sUrl[0] == 'h' && sUrl[1] == 't' && sUrl[2] == 't' && sUrl[3] == 'p' && sUrl[4] == ':' && sUrl[5] == '/' && sUrl[6] == '/') // Check if starts with 'http://'
        {
            for(unsigned int c = 7; c < sUrl.size(); c++)
            {
                tUrl += sUrl[c];
            }
        }
        else
        {
            tUrl = sUrl;
        }
    
        for(unsigned int c = 0; c < tUrl.size(); c++)
        {
            if(tUrl[c] == '/')
                break;
            Host += tUrl[c];
        }
    
        Http::Host = Host;
    
        return Host;
    }
    

    Allerdings bekomme ich bei dieser anfrage immer den http-error-code 400 zurück (invalid request - der server hat die anfrage nicht "verstanden")

    nun... ich hab mir einfach mal wireshark genomm und einmal nen packet von firefox gesniff und einmal das von mir ...

    und was raus kommt hier 😉

    einmal das packet von firefox (also so wie es wahrscheinlich sein sollte):
    http://img827.imageshack.us/img827/9964/rightux.jpg

    und einmal mein packet...
    http://img600.imageshack.us/img600/5558/false.jpg

    so leute 😉 wär echt super toll wenn mir einer sagen könnte was ich da falsch dran mache ...

    thx mfg 😉



  • Zwar nicht das Problem, aber -> Augenkrebs!

    if(sUrl[0] == 'h' && sUrl[1] == 't' && sUrl[2] == 't' && sUrl[3] == 'p' && sUrl[4] == ':' && sUrl[5] == '/' && sUrl[6] == '/') // Check if starts with 'http://'
    

    zu

    if(sUrl.find("http://") == 0)
    


  • Was ist denn dieser zweite "Hypertext Transfer Protocol" Abschnitt auf dem Bild von deinem Paket, das gehört doch nicht dahin, oder? Die Hex-Daten darin heißen "fertig". Ist dir da doch irgendwie noch was rein gerutscht? Im Code hier sehe ich nix verkehrtes.



  • Ist wohl ein "\n" zuviel.



  • Auch nicht das Problem, aber: SendAll macht kein Error-Checking, und das selbe was du bei SendAll machst (in Schleife aufrufen bis alles gesendet wurde) musst du bei recv() auch machen.

    Bzw. eigentlich nur bei recv(), denn send() verschickt bei blocking Sockets immer alles, da kann man sich die Schleife auch sparen. Bei recv() wirst du allerdings definitiv ein Problem bekommen, wenn die Antwort mal etwas grösser wird.



  • @fdfdg das frage ich mich ja auch^^... aber da ist eigentlich nichts zwischengerutscht...

    @HighLigerBiMBam und wo bitte ;)?

    @hustbaer mhh jo ok... aber im moment hab ich halt noch nen viel grösseres problem, als das ich nicht die komplette antwort bekomme^^

    thx mfg



  • GET HTTP 1.1 -> Pfad / fehlt und hier auch HTTP**/**1.1.
    GET / HTTP/1.1 muss es heissen.



  • hey danke deine antwort war echt hilfreich...
    also es lag an folgendem...

    Meine version:

    GET / HTTP 1.1
    

    Und so muss es sein:

    GET / HTTP/1.1
    

    danke bis hier hin 😉 und wenn mir jetzt noch einer sagen könnte wie ich mit großen tcp antworten umgehe bin ich wirklich sehr dankbar 😉

    mfg



  • Http Noob schrieb:

    Hey Leute 😉
    ...naja die grundlagen kann ich aber eigentlich (oop und klassen & syntax etc)...

    Natürlich 😃

    Sieht man auch gut an deinem code.
    Kleines Beispiel:

    Http Noob schrieb:

    string Http::GetSubHost(string sUrl) // Example: 'http://google.de/index.php' -> 'google.de'
    {
        string tUrl;
        string bUrl;
        string Host;
        if(sUrl[0] == 'h' && sUrl[1] == 't' && sUrl[2] == 't' && sUrl[3] == 'p' && sUrl[4] == ':' && sUrl[5] == '/' && sUrl[6] == '/') // Check if starts with 'http://'
        {
            for(unsigned int c = 7; c < sUrl.size(); c++)
            {
                tUrl += sUrl[c];
            }
        }
        else
        {
            tUrl = sUrl;
        }
    
        for(unsigned int c = 0; c < tUrl.size(); c++)
        {
            if(tUrl[c] == '/')
                break;
            Host += tUrl[c];
        }
    
        Http::Host = Host;
    
        return Host;
    }
    

    Alternative:

    std::string trim(const std::string& url) {
    	std::string host(url);
    	if (host.find("http://")==0)
    		host.erase(0,7);
    	return host.substr(0,host.find("/"));
    }
    


  • Sehr schön du schlaumeier^^

    Da ich keine lust hatte mich in die methoden der strings einzulesen hab ichs einfach selfmade erstma gemacht ...



  • Http Noob schrieb:

    und wenn mir jetzt noch einer sagen könnte wie ich mit großen tcp antworten umgehe bin ich wirklich sehr dankbar 😉

    Du musst recv in einer Schleife aufrufen und zwischen 1. Transfer-Encoding: chunked, 2. Content-Length und 3. Simple (gulp) unterscheiden.

    Das wirst du nicht in einem Tag hinkriegen.

    also etwa so:
    recv bis der header komplett ist, dann den header analysieren und dann wie oben angedeutet fortfahren.



  • Das ist doch in dem Artikel gut erklärt:

    http://www.c-plusplus.net/forum/169861



  • @EOP: Connection=Close und Content-Length sind relativ einfach hinzubekommen. Und Transfer-Encoding: chunked muss man ja nicht akzeptieren - gibt ja auch noch HTTP 1.0.



  • naja ihr habt mir mit euren tipps schonmal sehr gehilfen bisher 🙂
    Ich werde da morgen einfach nen bischen rumprobiern werde das schon irgendwie hinbekommen^^

    thx


Anmelden zum Antworten