Seite 1 von 3

Datei runterladen

Verfasst: So Jul 01, 2012 2:48 pm
von Kmitska
Hallo Leute,

ich möchte gerne paar Dateien von einem Server runterladen.
Als Beispiel habe ich mir dieses Bild hier ausgesucht:

Bild
Quelle: http://www.linux-mag.com/s/i/topics/tux.jpg

Das Problem ist: Ich habe keine Ahnung wie das geht, im Internet verstehe ich das ganze nicht.

Und wenn möglich:
Wie kann ich die Datei anzeigeigen lassen, ohne ihn zu speichern?

Hoffentlich könnt Ihr mir helfen/Tipps geben.

Grüße,
Kmitska

Re: Datei runterladen

Verfasst: So Jul 01, 2012 6:49 pm
von cloidnerux
Das Problem ist: Ich habe keine Ahnung wie das geht, im Internet verstehe ich das ganze nicht.
Du brauchst entweder was wie "curl" oder du rufst Programme wie "wget" im Hintergrund auf.
Wie kann ich die Datei anzeigeigen lassen, ohne ihn zu speichern?
Gar nicht. Du brauchst die Daten irgendwie lokal auf deinem Rechner, also entweder speicherst du die Daten in deinem RAM oder auf der Festplatte, ohne geht nicht.

Re: Datei runterladen

Verfasst: So Jul 01, 2012 8:28 pm
von Fisherman
Hallo Leute,
ich möchte gerne paar Dateien von einem Server runterladen.
Als Beispiel habe ich mir dieses Bild hier ausgesucht:
Da du dies in C/C++ gepostet hast, gehe ich mal davon aus das du es auch in dieser Sprache(n) umsetzen möchtest :
Da mit "Server" nicht das gewünschte Protokoll erläutert wurde, hier mal eine Anleitung um einen Webserver anzusprechen (http). Grundlagen der Netzwerkprogrammierung bei Beej's Network Guide.
Ich habe keine Ahnung wie das geht, im Internet verstehe ich das ganze nicht.
Ein Tip wäre dich mit dem OSI Modell vertraut zu machen. Danach mit den gewünschten Protokollen HTTP,FTP etc ...

Viel Spaß ;)

PS: Hab noch etwas gefunden - Quellcode anschauen

Re: Datei runterladen

Verfasst: So Jul 01, 2012 9:20 pm
von Kmitska
cloidnerux hat geschrieben:
Das Problem ist: Ich habe keine Ahnung wie das geht, im Internet verstehe ich das ganze nicht.
Du brauchst entweder was wie "curl" oder du rufst Programme wie "wget" im Hintergrund auf.
Wie kann ich die Datei anzeigeigen lassen, ohne ihn zu speichern?
Gar nicht. Du brauchst die Daten irgendwie lokal auf deinem Rechner, also entweder speicherst du die Daten in deinem RAM oder auf der Festplatte, ohne geht nicht.
Ja, ich meinte RAM. (Mein Fehler)
Und "wget", geht das auch unter Windows?

Aber das mit RAM wäre mir eigentlich lieber, da ich das Bild nur anzeigen lasse.
EDIT: Wie kann ich "wget" selber schreiben?

Re: Datei runterladen

Verfasst: So Jul 01, 2012 9:27 pm
von cloidnerux
Ja, ich meinte RAM. (Mein Fehler)
Und "wget", geht das auch unter Windows?

Aber das mit RAM wäre mir eigentlich lieber, da ich das Bild nur anzeigen lasse.
EDIT: Wie kann ich "wget" selber schreiben?
Soo, hier ist der Punkt, wo man dir sagen muss: Informiere dich oder lass es sein.
Das Internet und HTTP sind nicht furchtbar kompliziert, aber zu Kompliziert um es dir hier in einem Thread Detailgenau zu erklären. Es gibt genug Quellen, die auch von Fisherman schon aufgeführt wurden, die hinreichend genau beschreiben, was du suchst.

Auch habe ich dir curl, bzw libcurl schon ans herzgelegt, das implementiert ca das, was du haben willst. Ansonsten gibt es für Windows auch noch 1000 und ein Weg an Daten zu kommen, entweder über ActiVeX und ner IE instanz, über Windows Boardmittel oder über nem Socket, was du auch immer willst.
Aber das ganze ist kein 5 Minuten Projekt, wo du ein paar Zeilen Code zurecht tippen kannst und ich habe auch keine Lust dir die Grundlagen zu erklären.

Also, bitte lese dir die entsprechenden Quellen durch, oder lass es sein.

MfG cloidnerux.

Re: Datei runterladen

Verfasst: Mo Jul 02, 2012 4:46 pm
von Xin
Kmitska hat geschrieben:EDIT: Wie kann ich "wget" selber schreiben?
Du schreibst doch einen Crawler... Du kannst Websites runterladen? Dann kannst Du auch andere Daten runterladen - das Protokoll ändert sich nicht.

Aber Du musst es halt mal gründlich lesen. :-)

Re: Datei runterladen

Verfasst: Mi Jul 04, 2012 10:25 pm
von Kmitska
Xin hat geschrieben:
Kmitska hat geschrieben:EDIT: Wie kann ich "wget" selber schreiben?
Du schreibst doch einen Crawler... Du kannst Websites runterladen? Dann kannst Du auch andere Daten runterladen - das Protokoll ändert sich nicht.

Aber Du musst es halt mal gründlich lesen. :-)
Danke Dir. :)

Also habe jetzt einiges raus bekommen, doch beim "Abfangen" habe ich Probleme.
In Header wird die Länge mitgeteilt:

Code: Alles auswählen

Content-Lenght: 30308
Um das Bild abzufangen habe ich dies ausprobiert:

Code: Alles auswählen

int main()
{
    Socket sock;
    sock.create();
    sock.connect("airtrake.square7.ch", 80);
    sock.send("GET http://airtrake.square7.ch/webseite/community.PNG HTTP/1.1\r\n");
    sock.send("Host: airtrake.square7.ch\r\n");
    sock.send("\n");

    string recv,img;
    sock.recv(recv);

    for(int n=0; n<=(30308/1024); n++){
        sock.recv(recv);
        img += recv;
    }
    ofstream file("image.png");
    file << img;
    return 1;
}
Doch beim Abspeichern kommt eine fehlerhafte Datei raus.
Wo mache ich falsch?

Und die Socket Klasse aus "C++ von A bis Z":
Header:

Code: Alles auswählen

#ifndef SOCKET_H_
#define SOCKET_H_
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>

using namespace std;

// Max. Anzahl Verbindungen
const int MAXCONNECTIONS = 5;
// Max. Anzahl an Daten die aufeinmal empfangen werden
const int MAXRECV = 1024;

// Die Klasse Socket
class Socket {
   private:
   // Socketnummer (Socket-Deskriptor)           
   int m_sock; 
   // Struktur sockaddr_in
   sockaddr_in m_addr;
   
   public:
   // Konstruktor
   Socket();
   // virtueller Destruktor
   virtual ~Socket();

   // Socket erstellen - TCP
   bool create();
   // Socket erstellen - UDP
   bool UDP_create();
   bool bind( const int port );
   bool listen() const;
   bool accept( Socket& ) const;
   bool connect ( const string host, const int port );
   // Datenübertragung - TCP
   bool send ( const string ) const;
   int recv ( string& ) const;
   // Datenübertragung - UDP
   bool UDP_send( const string, const string,
                  const int port ) const;
   int UDP_recv( string& ) const;
   // Socket schließen
   bool close() const;
   // WSAcleanup()
   void cleanup() const;
   bool is_valid() const { return m_sock != -1; }
   // für select()
   int get_m_sock() const { return m_sock; }
   void set_m_sock( int nr ) { m_sock = nr; }  
   
};

// Exception-Klasse
class SockExcept {
   private:
   string except;
   
   public:
   SockExcept( string s ) : except( s ) {};
   ~SockExcept() {};
   string get_SockExcept() { return except; }
};

#endif
Cpp:

Code: Alles auswählen

// socket.cpp
#include <cstdlib>
#include <iostream>
#include <cstring>
#include "socket.h"
using namespace std;

Socket::Socket() : m_sock(0) { }

Socket::~Socket() {
   if ( is_valid() )
      ::close( m_sock );
}

bool Socket::create() {
   m_sock = ::socket(AF_INET,SOCK_STREAM,0);
   if (m_sock < 0) {
      throw SockExcept("Fehler beim Anlegen eines Socket");
   }
   int y=1;
   setsockopt( m_sock, SOL_SOCKET,
               SO_REUSEADDR, &y, sizeof(int));
   return true;
}

bool Socket::UDP_create() {
   m_sock = ::socket(AF_INET,SOCK_DGRAM,0);
   if (m_sock < 0) {
      throw SockExcept("Fehler beim Anlegen eines Socket");
   }
   return true;
}

bool Socket::bind( const int port ) {
   if ( ! is_valid() ) {
      return false;
   }
   m_addr.sin_family = AF_INET;
   m_addr.sin_addr.s_addr = INADDR_ANY;
   m_addr.sin_port = htons ( port );

   int bind_return = ::bind ( m_sock,
      ( struct sockaddr * ) &m_addr, sizeof ( m_addr ) );
   if ( bind_return == -1 ) {
      return false;
   }
   return true;
}

bool Socket::listen() const {
   if ( ! is_valid() ) {
      return false;
   }
   int listen_return = ::listen ( m_sock, MAXCONNECTIONS );
   if ( listen_return == -1 ) {
      return false;
   }
  return true;
}

bool Socket::accept ( Socket& new_socket ) const {
   int addr_length = sizeof ( m_addr );
   new_socket.m_sock = ::accept( m_sock,
      ( sockaddr * ) &m_addr, ( socklen_t * ) &addr_length );
   if ( new_socket.m_sock <= 0 )
      return false;
   else
      return true;
}

bool Socket::connect( const string host, const int port ) {
   if ( ! is_valid() )
      return false;
   struct hostent *host_info;
   unsigned long addr;
   memset( &m_addr, 0, sizeof (m_addr));
   if ((addr = inet_addr( host.c_str() )) != INADDR_NONE) {
       memcpy( (char *)&m_addr.sin_addr,
               &addr, sizeof(addr));
   }
   else {
       host_info = gethostbyname( host.c_str() );
       if (NULL == host_info) {
          throw SockExcept("Unbekannter Server");
       }
       memcpy( (char *)&m_addr.sin_addr, host_info->h_addr,
                host_info->h_length);
   }
   m_addr.sin_family = AF_INET;
   m_addr.sin_port = htons( port );

   int status = ::connect ( m_sock,
      ( sockaddr * ) &m_addr, sizeof ( m_addr ) );

  if ( status == 0 )
    return true;
  else
    return false;
}

bool Socket::send( const string s ) const {
   int status = ::send ( m_sock, s.c_str(), s.size(),  0 );
   if ( status == -1 ) {
      return false;
   }
   else {
      return true;
   }
}

int Socket::recv ( string& s ) const {
  char buf [ MAXRECV + 1 ];
  s = "";
  memset ( buf, 0, MAXRECV + 1 );

  int status = ::recv ( m_sock, buf, MAXRECV, 0 );
  if ( status > 0 || status != -1 ) {
     s = buf;
     return status;
  }
  else {
     throw SockExcept("Fehler in Socket::recv");
     return 0;
  }
}

bool Socket::UDP_send( const string addr, const string s, const int port ) const {
   struct sockaddr_in addr_sento;
   struct hostent *h;
   int rc;

   h = gethostbyname(addr.c_str());
   if (h == NULL) {
      throw SockExcept("Unbekannter Host?");
   }
   addr_sento.sin_family = h->h_addrtype;
   memcpy ( (char *) &addr_sento.sin_addr.s_addr,
            h->h_addr_list[0], h->h_length);
   addr_sento.sin_port = htons (port);
   rc = sendto( m_sock, s.c_str(), s.size(), 0,
                 (struct sockaddr *) &addr_sento,
                  sizeof (addr_sento));
   if (rc == -1) {
      throw SockExcept(
         "Konnte Daten nicht senden - sendto()");

   }
   return true;
}

int Socket::UDP_recv( string& s ) const {
   struct sockaddr_in addr_recvfrom;
   int len, n;
   char buf [ MAXRECV + 1 ];
   s = "";
   memset ( buf, 0, MAXRECV + 1 );
   len = sizeof (addr_recvfrom);
   n = recvfrom ( m_sock, buf, MAXRECV, 0,
                  (struct sockaddr *) &addr_recvfrom,
                  ( socklen_t * )&len );
   if (n == -1){
      throw SockExcept("Fehler bei recvfrom()");
      return 0;
   }
   else {
      s = buf;
      return n;
   }
}

void Socket::cleanup() const { }

bool Socket::close() const {
   ::close(m_sock);
   cleanup();
   return true;
}
Danke im Voraus.

Re: Datei runterladen

Verfasst: Mi Jul 04, 2012 10:29 pm
von cloidnerux
Du hast wrsl durch die Verwendung von strings eine Null-Terminierte Datei und höchst wahrscheinlich noch Formatoptionen, die dir Automatisch deine Daten verwursten. Das ist natürlich nicht erwünscht, da du ja keinen text sondern Binäre Daten empfängst.
Folglich ist die Verwendung von einem unsigned char array angebracht, welches Dynamisch durch malloc oder ähnliches den erforderlichen speicher bereitstellt. Dadurch erst kannst du dir sicher sein, dass deine Daten korrekt übertragen werden.

Re: Datei runterladen

Verfasst: Do Jul 05, 2012 8:00 pm
von Kmitska
Habe das nun so gemacht:

Code: Alles auswählen

int main()
{
    Socket sock;
    sock.create();
    sock.connect("airtrake.square7.ch", 80);
    sock.send("GET http://airtrake.square7.ch/webseite/community.PNG HTTP/1.1\r\n");
    sock.send("Host: airtrake.square7.ch\r\n");
    sock.send("\n");

    char* gesamt = new char[30308];
    char* antwort = new char [1024];
    sock.recv(*antwort);
    cout << antwort;

    for(int i=0; i<=(30308/1024); i++){
        sock.recv(*antwort);
        strcat(gesamt, antwort);
    }

    delete antwort;

    ofstream file("image.png");
    file << gesamt;

    delete gesamt;
    return 1;
}
Die Datei ist aber immernoch fehlerhaft, hier ist die umgeschriebene Funktion Socket::recv();:

Code: Alles auswählen

int Socket::recv ( char& s ) const {
  char buf [ MAXRECV + 1 ];
  s = 0;
  memset ( buf, 0, MAXRECV + 1 );

  int status = ::recv ( m_sock, buf, MAXRECV, 0 );
  if ( status > 0 || status != -1 ) {
     strcat(&s, buf);
     return status;
  }
  else {
     throw SockExcept("Fehler in Socket::recv");
     return 0;
  }
}
Was könnte da schief gehen? :/

Re: Datei runterladen

Verfasst: Do Jul 05, 2012 8:13 pm
von cloidnerux
Was könnte da schief gehen? :/
Du nutzt immer noch String-Funktionen. strcat ist für Strings, also texte. Das Dingen addiert automatisch Null-Bytes.
Verwende Funktionen wie memcpy oder ähnliche. Denk immer daran, du willst binäre Daten verarbeiten und keine Texte.

Du könntest aber auch direkt deinen Buffer in die Datei schreiben.