PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Datei wird mittels socket nur zum teil heruntergeladen


freeze
23.12.2004, 11:53
Hey @all,

und zwar habe ich vor, eine Datei per HTTP herunterzuladen, OS ist Linux.
Mein Problem ist nun, das er die Datei nicht komplett herunterlädt sondern beispielsweise nur 2782 bytes von insgesamt ca. 28600. Kann mir jemand helfen, wo ich da das Problem habe.

hier der code:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h> // für write
#include <fstream>
#include <arpa/inet.h>
using namespace std;

const unsigned int BUFFER_SIZE = 1024;

class CSocketError {
private:
string message;
CSocketError() {}

public:
CSocketError(string _message) : message(_message) {
}
~CSocketError() {}
const char* what() const {
return this->message.c_str();
}
};

class CSocket {
private:
bool socket_open;
int sockfd;
int err;
string server;
string url;
int server_port;
int bytes;

public:
CSocket();
CSocket(string, int port = 80);
~CSocket();
void connect2();
void get(string);
void close2();
};

CSocket::CSocket() {
}

CSocket::CSocket(string server, int port) {
this->socket_open = false;
this->server = server;
this->server_port = port;
this->bytes = 0;
}

CSocket::~CSocket() {
}

void CSocket::connect2() {
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
throw CSocketError("ERROR: TCP socket can't beo opened");

// char domain[] = "images.ucomics.com";
hostent * host;
host = gethostbyname(this->server.c_str());
struct in_addr ip;
ip = *(struct in_addr*) host->h_addr;
// Verbindung zum Webserver aufbauen
struct sockaddr_in zieladdr;
zieladdr.sin_family = AF_INET;
zieladdr.sin_port = htons(this->server_port);
zieladdr.sin_addr = ip; //.s_addr = inet_addr("131.220.4.1");
err = connect(sockfd,(struct sockaddr*) &zieladdr, sizeof(sockaddr_in));
if(err < 0)
throw CSocketError("ERROR: Can't connect to '" + this->server + "'");
}

void CSocket::get(string url) {
this->url = url;
string GET_Method = "GET " + this->url + " HTTP/1.1\n\n";
cout << "GET: >>>" << GET_Method << "<<<" << endl;
//this->err = write(this->sockfd, GET_Method.c_str(), GET_Method.length());
this->err = send(this->sockfd, GET_Method.c_str(), GET_Method.length(), 0);
cout << "ERROR-NR: " << err << endl;
// if(err == GET_Method.length())
if(err < 0)
throw CSocketError("ERROR: The request wasn't successfully send!");

fstream file("test.gif", ios::out | ios::binary);
int i=0;
bool do_file_write = false;
for(;;) {
char buffer[BUFFER_SIZE];
memset(buffer, '\0', BUFFER_SIZE);
// i = read(this->sockfd, buffer, sizeof(buffer));
i = recv(this->sockfd, buffer, sizeof(buffer), 0);
this->bytes += i;
if(i<sizeof(buffer) && i != sizeof(buffer)) {
buffer[i] = '\0';
}
else if(i == sizeof(buffer)) {
// cout << "Buffer can't terminated" << endl;
}
else
cout << "Buffer weren't terminated" << endl;
/* buffer[sizeof(buffer)] = '\0';*/

// if(do_file_write)
cout << "I_Recv: " << i << endl;
if(i == 0)
break;
file << buffer;

/* string tmp = buffer;
cout << "Text: " << tmp << endl;
cout << "SIZE: " << tmp.length() << endl;
cout << "---------------------" << endl;*/
/* if(!do_file_write && buffer[0] == '\r' && buffer[1] == '\n') {
do_file_write = true;
cout << "Found File-Begin" << endl;
}*/
}

err = close(sockfd);
if(err < 0)
throw CSocketError("ERROR: The socket can't be closed!");
this->socket_open = false;
cout << this->bytes << " Bytes were received!" << endl;
}

void CSocket::close2() {
if(this->socket_open)
close(this->sockfd);
}


int main(int argc, char *argv[]) {
cout << "Starting connecting" << endl;
CSocket* sock = new CSocket("www.google.de");
try {
cout << "Connecting" << endl;
sock->connect2();
cout << "Sending Request" << endl;
sock->get("http://www.google.de/logos/winter_holiday_04_sah.gif");
cout << "Close Connection" << endl;
sock->close2();
}
catch(CSocketError& e) {
cout << e.what() << endl;
}
cout << "Finished" << endl;

return 0;
}


Vielen Dank im Voraus
Lg freeze


Jan Krüger
23.12.2004, 12:54
Deine Schleife zum Schreiben verstehe ich nicht so ganz. Am einfachsten geht es so: Dinge in den Buffer lesen und an die Datei anhängen, bis der recv()- oder read()-Aufruf 0 (EOF) zurückgibt. Du kannst die Dateiinhalte allerdings nicht als normale Strings behandeln, denn in Binärdateien können Nullbytes auftauchen! file << buffer; ist also nicht.
Ganz abgesehen davon ist dein HTTP-Request nicht gültig -- HTTP/1.1-Anfragen müssen mindestens den Host:-Header haben (und der RFC sieht CRLF als Zeilenende vor, nicht nur LF).

freeze
23.12.2004, 13:25
Meinst Du die Zeile zum schreiben in die Datei, oder zum Absetzen der GET-Anfrage?

freeze
23.12.2004, 13:29
Achso, Du meinst wohl diesen Ausdruck (empfangen der Daten und danach abwärts in die Datei), ich habe den Code mal etwas gesäubert.

Der Wert von BUFFER_SIZE ist 1024, dieser Code-Teil wird wahrscheinlich das Problem verursachen:

for(;;) {
char buffer[BUFFER_SIZE];
memset(buffer, '\0', BUFFER_SIZE);
i = recv(this->sockfd, buffer, sizeof(buffer), 0);
this->bytes += i;

if(i<sizeof(buffer) && i != sizeof(buffer)) {
buffer[i] = '\0';
}
cout << "I_Recv: " << i << endl;
if(i == 0)
break;

file << buffer;
}


Lg freeze

Jan Krüger
23.12.2004, 18:13
Das ändert alles nichts an den Sachen, die ich gesagt habe. Strings und EOF-Behandlung und so.

freeze
23.12.2004, 20:18
OK, also ich habe das jetzt mal so umgeändert. Die Änderungen sind in ROT geschrieben.

for(;;) {
memset(this->buffer, 0, BUFFER_SIZE);
i = recv(this->sockfd, this->buffer, BUFFER_SIZE, 0);
this->bytes += i;
cout << this->bytes << " Bytes received" << endl;

if(i <= 0)
break;

file.write(buffer, i);
}


So, es funktioniert jetzt fast perfekt. Jetzt fehlt mir nur noch das ich den Header irgendwie wegbekomme, hat jemand einen Tip? Beziehungsweise den Header auswerten, weil ja dort steht, wie viele Bytes die Datei hat, so das ich nachher quasi eine Prüfsumme mit der tatsächlich geschriebenen Bytes prüfen kann.

Lg freeze

Felix Kaiser
24.12.2004, 11:49
Bevor du in die Datei schreibst, solltest du den Header in einem Puffer zwischenspeichern. Das Ende des Headers erkennst du an einer leeren Zeile (also 2xCRLF). Du brauchst dann nur noch den übrigen Header zeilenweise zerlegen.

freeze
24.12.2004, 13:52
Ja, danke, so hatte ich auch den Ansatz, bin eh bis in der nacht gesessen, bis ich mir meine Klasse geschnitzt habe. Vielen Dank an alle, falls jemand das Beispiel braucht, einfach eine PM schreiben.

Lg freeze

P.S.: Schöne Weihnachten an alle