Simple TXT Dateien aus dem Internet auslesen
-
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 angepasstDaher 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 dichIch 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 constAuch 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