Simple TXT Dateien aus dem Internet auslesen



  • So..mal wieder ne Frage:
    Ic habe vor kurzem mit einem Kumpel ein kleines Sloganizer Proggi geschrieben. Man gibt einen Begriff ein und es formt damit einen nicht immer 100% sinnigen Slogan. Mittlerweile habe ich auch eine schöne FLTK Oberfläche dafür erstellt und uns kan die Idee das ganze noch ein Stückchen zu verbessern - Die Idee:

    Das Programm ruft die unterschiedlichen Slogans aus einer auf meiner Homepage befindlichen .txt Datei, die jeder mittels eines bereitgestellten PHP scripts erweitern kann ab (das script habe ich schon). Nun hoffe ich, dass ihr mir villeicht erklären könnt wie man diesen Zugriff bewältigen kann, oder mir einen Link zu einer Anleitung posten könnt. Allerding muss es mit C++ sein, weil ich kein Perl/Python/etc. kann.

    Kurz: Wie kann ich eine Datei im Internet Zeilenweise auslesen?

    Vielen Dank für eure Hilfe



  • Hallo,

    ich gehe mal davon aus das ihr mit C++ arbeitet? Mit Standard C++ geht das gar nicht. Daher: Welches Betriebssystem? Generell lässt sich das jedoch recht einfach lösen in dem man sich mit dem HTTP-Protokoll vertraut macht sich mit dem Server auf Port 80 verbindet und eine GET Anweisung sendet. Oder man nutzt eine Funktion des Betriebssystems. Ich würde sagen du benutzt mal die Forensuchen, denn ich bin mir sicher ähnliche Fragen gabs schon öfter 🙂

    Aufjedenfall kann ich dir sagen: Es ist möglich 🙂

    Gruß Patrick

    Edit:

    Hier eine kleine Einführung in Winsock( Windows ): www.c-worker.ch



  • ich benutze windows (xp)

    mit winsock habe ich auch schonmal ein klitzekleines chatprogramm geschrieben, ich hoffte nur, dass es möglicherweise eine noch einfachere Variante gäbe



  • alfonsospringer schrieb:

    mit winsock habe ich auch schonmal ein klitzekleines chatprogramm geschrieben, ich hoffte nur, dass es möglicherweise eine noch einfachere Variante gäbe

    Gibt es meines Wissens nicht, du kannst die höchsten eine Klasse/Komponente suchen, die die WinSock-Funktionen kapselt.



  • Hi,
    habe nur kurz den Code von www.c-worker.ch für dich angepasst 🙂 Daher Formatierung usw... Nicht so schön 😃

    #include <windows.h>
    #include <winsock.h>
    #include <stdio.h>
    
    #pragma comment( lib, "ws2_32.lib" )
    
    //Prototypen
    int startWinsock(void);
    
    int main()
    {
      long rc;
      SOCKET s;
      SOCKADDR_IN addr;
      char buf[1024];
    
      // Winsock starten
      rc=startWinsock();
    
      // Socket erstellen
      s=socket(AF_INET,SOCK_STREAM,0);
    
      // Verbinden
      memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten
      addr.sin_family=AF_INET;
      addr.sin_port=htons(80); // HTTP = 80
    
      /*
    
    	ping www.google.de
    
    	Ping www.l.google.com [209.85.129.147] mit 32 Bytes Daten:
    
      */
      addr.sin_addr.s_addr=inet_addr("209.85.129.147");  // Evtl. musst du dich über  Auflösung von Adressen erkundigen :)
    
      rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
    
      // Daten austauschen
      char ToSend[256];
      sprintf( ToSend, "GET /index.php HTTP/1.0\n\n" );
      // \n\n !!! WICHTIG !!
    
      send(s,ToSend,strlen(ToSend),0);
      while(rc!=SOCKET_ERROR)
      {
        rc=recv(s,buf,1023,0);
        if(rc==0)
        {
          printf("Server hat die Verbindung getrennt..\n");
          break;
        }
        if(rc==SOCKET_ERROR)
        {
          printf("Fehler: recv, fehler code: %d\n",WSAGetLastError());
          break;
        }
        buf[rc]='\0';
        printf("\nServer antwortet: %s\n\n\n",buf);
      }
      closesocket(s);
      WSACleanup();
      return 0;
    }
    
    int startWinsock(void)
    {
      WSADATA wsa;
      return WSAStartup(MAKEWORD(2,0),&wsa);
    }
    

    Gruß Patrick

    PS: Gibt natürlich bei Google keine index.php, aber geht ja ums Prinzip. Kannst den Code ja vergleichen: http://www.google.de/index.php



  • Wunderbar -> Vielen Dank



  • 🙂 Ich hoffe dir ist auch aufgefallen, dass die Datei in Blöcken versendet wurde. Du musst also wenn du den Inhalt in eine Datei speichern willst immer Anhängen und evtl. überflüssiges wie die Statusmeldungen des Webservers rausfiltern, sollte aber kein Problem mehr sein 🙂



  • nimm lieber libcurl, anstelle etwas eigenes zu schreiben. Der Code da oben ist zB fehlerhaft (also nicht als Code, aber in der Benutzung von HTTP) und wertet auch die Rückgabe nicht aus...



  • kennst du da ein tutorial?



  • rüdiger schrieb:

    nimm lieber libcurl, anstelle etwas eigenes zu schreiben. Der Code da oben ist zB fehlerhaft (also nicht als Code, aber in der Benutzung von HTTP) und wertet auch die Rückgabe nicht aus...

    Sollte auch nur als Beispiel dienen 🙂

    alfonsospringer schrieb:

    kennst du da ein tutorial?

    Google? 🙂

    Gruß Patrick



  • thx, ich hab mir jetzt meine eigene kleine klasse zur erstellung von einfachen winsock clients zusammengeschustert, und ich denke sie funktioniert ganz gut

    #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;
        };
    
    };
    

    Was sagt ihr dazu? Ich finde sie macht das erstellen von ganz billigen winsock Verbindungen einfacher. Das sieht dann so aus:

    int main()
    {
      char buf[255];
      client x("127.0.0.1", 12345); // IP - PORT
      data("hallo"); //sendet "hallo" an server
      buf = data(); //speichert antwort des servers in buf
    };
    


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


Anmelden zum Antworten