Simple TXT Dateien aus dem Internet auslesen



  • Hi,
    man sieht du bemühst dich 👍 Ich hätte die Klasse jedoch etwas anders gemacht und zwar lässt sich da durch Vererbung was sehr tolles machen 🙂

    Du erstellst eine Basisklasse:

    class ClientSocket
    {
    //...
    };

    Und von dieser leitest du dann ab:

    class Client : public ClientSocket
    {
    //...
    };

    Das ist so natürlich noch sinnlos und wird erst brauchbar, wenn du hier mit virtuellen Funktionen arbeitest, ich mache dir nacher ein vollständiges Beispiel 🙂

    Noch ein Tipp: Du solltest anstatt client(string ip, int port) lieber
    client( const string& ip, int port) schreiben. Denn dann brauch kein neues Objekt erzeugt werden. Da das Objekt nicht verändert wird dann das ganze noch const 🙂 Auch halt eich es für sinnvoll die Klasse in eine Header (.h) und .cpp Datei aufzuteilen...

    Gruß Patrick

    Edit: Deine Klasse hat noch ein paar Fehler, hab sie gerade übersehen. Zum Beispiel schließt du den Socket nicht wieder mit closesocket...



  • Hi,

    hab jetzt mal was gebastelt 🙂

    #define _CRT_SECURE_NO_DEPRECATE
    
    #include <iostream>
    #include <string>
    #include <winsock.h>
    
    #pragma comment( lib, "ws2_32.lib" )
    
    class SocketClient
    {
    	protected:
    		long rc;
    		SOCKET s;
    		SOCKADDR_IN addr;
    		char buf[256];
    
    	public:
    		SocketClient( void )
    		{
    			rc = startWinsock();
    		}
    
    		~SocketClient( void )
    		{
    			if ( s ) closesocket( s );
    			WSACleanup();
    		}
    
    	public:
    		int Connect( const std::string& Ip, const int Port )
    		{
    			if( rc != 0 )
    			{
    				std::cerr << "Fehler: startWinsock, fehler code: " << rc << std::endl;
    				return 1;
    			}
    
    			s = socket(AF_INET,SOCK_STREAM,0);
    			if( s == INVALID_SOCKET )
    			{
    				std::cerr << "Fehler: Der Socket konnte nicht erstellt werden, fehler code: " << WSAGetLastError() << std::endl;
    				return 2;
    			}
    
    			// Verbinden
    			memset(&addr,0,sizeof(SOCKADDR_IN));
    			addr.sin_family = AF_INET;
    			addr.sin_port = htons( Port );
    			addr.sin_addr.s_addr = inet_addr( Ip.c_str() );
    
    			rc = connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
    
    			if( rc == SOCKET_ERROR )
    			{
    				std::cerr<< "Fehler: connect gescheitert, fehler code: " << WSAGetLastError() << std::endl;
    				return 3;
    			}
    
    			return 0;
    		}
    
    		int Start( void )
    		{
    			while( rc != SOCKET_ERROR )
    			{
    				rc = recv(s,buf,255,0);
    
    				if( rc == 0 )
    				{
    					std::cout << "Server hat die Verbindung getrennt..." << std::endl;
    					return 1;
    				}
    
    				if( rc == SOCKET_ERROR )
    				{
    					std::cerr << "Fehler: recv, fehler code: " << WSAGetLastError() << std::endl;
    					return 2;
    				}
    
    				buf[rc] = '\0';
    
    				Main();
    
    				OnRecieved( buf );
    			}
    
    			return 0;
    		}
    
    		int SendToServer( const std::string& Message )
    		{
    			return send( s, Message.c_str(), Message.size(), 0 );
    		}
    
    		virtual int Main( void )								=	 0;
    		virtual void OnRecieved( const std::string& Message )	=	 0;
    
    	private:
    		int startWinsock( void )
    		{
    			WSADATA wsa;
    			return WSAStartup(MAKEWORD(2,0),&wsa);
    		}
    };
    
    class Client : public SocketClient
    {
    	public:
    		virtual int Main( void )
    		{
    			/*
    				Haupt-Code...
    			*/
    			return 0;
    		}
    
    		virtual void OnRecieved( const std::string& Message )
    		{
    			std::cout << "Recieved: " << Message << std::endl;
    		}
    };
    
    int main ( void )
    {
    	Client Test;
    
    	if ( Test.Connect( "127.0.0.1", 80 ) == 0 )
    	{
    		Test.SendToServer( "GET /index.php HTTP/1.0\n\n" );
    		std::cout << "Verbunden!" << std::endl;
    		Test.Start();
    	}
    
    	return 0;
    }
    

    Also ich hätte es so ähnlich gemacht... So kannst du den Code aufjedenfall fürs nächste mal auch wieder benutzen. Außerdem hab ich das printf Zeugs rausgeschmissen, weil wir ja jetzt mit C++ arbeiten 🙂

    Hoffe es hilft dir

    Gruß Patrick



  • vielen dank für deine ganze mühe patrick - ich denke jetzt habe ich eine Ausgangsbasis für meine weiteren Studien

    😃



  • Kein Problem 🙂 Für die, die es noch interessiert. So lässt sich damit eine HTML... Datei runterladen...

    class Client : public SocketClient
    {
    	private:
    		std::ofstream Out;
    		std::string Temp;
    
    	public:
    		Client( void )
    		{
    			Out.open( "Recieved.html", std::ios::out | std::ios::app );
    		}
    
    		~Client( void )
    		{
    			Out << Temp.substr( Temp.find( "\r\n\r\n") + 4, Temp.length() ); // Schnelldurchlauf, über den Header...
    			Out.close();
    		}
    
    		virtual int Main( void )
    		{
    			return 0;
    		}
    
    		virtual void OnRecieved( const std::string& Message )
    		{
    			Temp += Message; // Sammeln der Datei-Blöcke...
    		}
    };
    
    int main ( void )
    {
    	Client Test;
    
    	if ( Test.Connect( "209.85.129.147", 80 ) == 0 ) // Google... Wie gesagt gethostbyname einbauen wäre noch ganz sinnvoll -> Google :)
    	{
    		Test.SendToServer( "GET /DATEI_EXISTIERT_SOWIESO_NICHT.PHP HTTP/1.0\n\n" );
    		Test.Start();
    	}
    	else
    	{
    		std::cerr << "Fehler beim Verbinden!" << std::endl;
    	}
    
    	std::cout << "Fertig." << std::endl;
    
    	return 0;
    }
    

    Ich denke jetzt hab ich alles 😃 😃

    🙂



  • @Dummie
    Bei HTTP nimmt man \r\n und nicht \n! Außerdem solltest du den Header interpretieren. Können ja Fehler auftreten oder der könnte dir die Daten chunked-Encoded liefern.

    Nicht umsonst empfehle ich libcurl. HTTP ist nicht ganz so einfach wie es auf den ersten Blick aussieht...

    alfonsospringer schrieb:

    vielen dank für deine ganze mühe patrick - ich denke jetzt habe ich eine Ausgangsbasis für meine weiteren Studien

    😃

    ich würde dir eher Boost.ASIO oder Boost.iostreams in Kombination mit Sockets empfehlen.

    Ansonsten gibt es glaube ich ein Artikel dazu im C++-Magazin.



  • rüdiger schrieb:

    @Dummie
    Bei HTTP nimmt man \r\n und nicht \n! Außerdem solltest du den Header interpretieren. Können ja Fehler auftreten oder der könnte dir die Daten chunked-Encoded liefern.

    Nicht umsonst empfehle ich libcurl. HTTP ist nicht ganz so einfach wie es auf den ersten Blick aussieht...

    alfonsospringer schrieb:

    vielen dank für deine ganze mühe patrick - ich denke jetzt habe ich eine Ausgangsbasis für meine weiteren Studien

    😃

    ich würde dir eher Boost.ASIO oder Boost.iostreams in Kombination mit Sockets empfehlen.

    Ansonsten gibt es glaube ich ein Artikel dazu im C++-Magazin.

    Hast schon recht, aber in erster Linie gehts ums Prinzip. Auf der anderen Seite warum sollte man so viel Aufwand betreiben um eine simple Textdatei runterzuladen? Entweder es hat geklappt oder nicht, was interessieren mich da noch Statusmeldungen oder sonstiger Krams. Und ja es gibt einen Artikel 🙂

    Edit 1: Zu schnell geschrieben... Rechtschreibung 😃
    Edit 2: Mit \r\n funktionierts nicht, das war wohl auch der Grund warum ich \n\n benutzt habe...



  • HTTP-Abfragen gehören definitiv zu den Sachen, die hier im Forum immer wieder versucht werden händisch zu machen und in 99% aller Fälle geht das in die Hose. Wie hier zum Beispiel in dem Thread. Ein einfaches \n ist kein Zeilentrenner im HTTP-Protokoll. Dafür nimmt man \r\n (am Ende der Anfrage eben \r\n\r\n). Einige Server könnten standardmäßig ein Host-Header-Field erwarten. Für HTTP/1.1 ist dies sogar vorgeschrieben.

    Die Statusmeldung sagt dir ja, ob es geklappt hat oder nicht. Außerdem sagt sie dir zB wie groß die Datei ist oder ob die Datei in einem Encoding verschickt wird. Dein Code zB lässt sich mit einem bösen Server in undefiniertes Verhalten bringen etc.

    Warum sich also die Mühe machen und das versuchen selbst zu implementieren, wenn man wohlgetestete und effizient implementierte Lösungen bereits hat (zB libcurl)?

    Lasst bitte die Finger davon Protokolle zu implementieren auf Basis von "Hören/Sagen". Wenigstens ein Blick in die RFC (oder Spec) sollte man tun!



  • Wenn ich ein einfach verständlcihes Libcurl Tutorial mit Installationsanleitung für Code::Blocks finden würde würde ich es sofort ausprobieren



  • Kann mir mal jemand erklären warum die Funktion zum empfangen von Daten in meiner Klasse nicht funktioniert?



  • alfonsospringer schrieb:

    Kann mir mal jemand erklären warum die Funktion zum empfangen von Daten in meiner Klasse nicht funktioniert?

    Nein.



  • Ich hoffe doch schwer, dass das ein Scherz sein sollte



  • erklärber schrieb:

    alfonsospringer schrieb:

    Kann mir mal jemand erklären warum die Funktion zum empfangen von Daten in meiner Klasse nicht funktioniert?

    Nein.

    Auch ich kanns dir nicht sagen, aber ich vermute der Fehler liegt daran, dass die Klasse gar nicht existiert... Für uns 😃 Trink nicht so viel Kaffee 🤡



  • 😃

    Alfonsospringer schrieb:

    #include <windows.h>
    
    #include <winsock2.h>
    
    #include <iostream>
    
    #include <string.h>
    
    using namespace std;
    
    class client
    {
        private:
        long rc;
        WSADATA wsa;
        SOCKET s;
        SOCKADDR_IN addr;
        int port;
        string ip;
        char se[256];
        char re[256];
    
        public:
        client(string ip, int port)
        {
            rc=WSAStartup(MAKEWORD(2,0),&wsa);
            if(rc!=0)
            {
                cout<<"Fehler: startWinsock, fehler code: "<<rc<<endl;
            }
            else
            {
                cout<<"Winsock gestartet!"<<endl;
            };
            s=socket(AF_INET,SOCK_STREAM,0);
            if(s==INVALID_SOCKET)
            {
                cout<<"Fehler: Der Socket konnte nicht erstellt werden, fehler code: "<<WSAGetLastError()<<endl;
            }
            else
            {
                cout<<"Socket erstellt!"<<endl;
            };
            memset(&addr,0,sizeof(SOCKADDR_IN));
            addr.sin_family=AF_INET;
            addr.sin_port=htons(port); // wir verwenden mal port 12345
            addr.sin_addr.s_addr=inet_addr(ip.c_str());
            rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
            if(rc==SOCKET_ERROR)
            {
                cout<<"Fehler: connect gescheitert, fehler code: "<<WSAGetLastError()<<endl;
            }
            else
            {
                cout<<"Verbunden mit "<<ip<<endl;
            };
        };
    
        void data(string data)
        {
            strcpy(se,data.c_str());
            send(s,se,data.length(),0);
        };
    
        char data()
        {
            recv(s,re,256,0);
            return re;
        };
    
    };
    

    Hier also nochmal die nicht existente Klasse

    Könnt ihr mir jetzt villeicht erklären, warum's nicht funktioniert?



  • alfonsospringer schrieb:

    Könnt ihr mir jetzt villeicht erklären, warum's nicht funktioniert?

    Was funktioniert nicht? Fehlermeldungen...?

    char data()
    {
        recv(s,re,256,0);
        return re;
    };  // Der ; ist überflüssig, aber wenn es dir gefällt...
    

    Ich würde mal vermuten, dein Rückgabewert ist falsch...

    Gruß
    Patrick



  • Ich denke da hasst du recht. Der Compiler meldet invalid conversion ...
    Aber eigentlich bekommt man durch die recv Funktion doch Daten des Typs char zurück, oder?


Anmelden zum Antworten