Sockets und das HTTP-Protokoll



  • hi,

    bin im Kapitel 6.4 und hab da alles fertig !
    Aber irgendwie und aus irgendeinem grund funktioniert der code bei mir nicht !

    Hab alles genauso, aber trotzdem geht es bis zur prozentanzeige, da steht dann eben 0% und dann kommt "Socket-Fehler #0: D"
    hab meinem code mit dem code von hier verglichen, finde aber nix und wenn ich den code, den ich hier downgeloadet hab, ausprobier, dann funktioniert er, bloß mein selbst geschriebener nicht !

    Verstehe ich nicht, weiß jemand rat, gibts noch irgendwas zu beachten ??

    Hier mein Code:

    #include <iostream>
    #include <fstream>
    #include <stdexcept>	// runtime_error
    #include <sstream>
    #include <string>
    #include <WinSock2.h>
    using namespace std;
    // Infos: http://www.c-plusplus.net/forum/viewtopic-var-t-is-169861.html
    
    // wenn während dem Senden ein Fehler auftritt
    runtime_error CreateSocketError()
    {
    	ostringstream temp;
    	int error = WSAGetLastError();
    	temp << "Socket-Fehler #" << error;
    	char *msg;
    
    	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    		reinterpret_cast<LPWSTR>(&msg), 0, NULL))
    	{
    		try
    		{
    			temp << ": " << msg;
    			LocalFree(msg);
    		}
    		catch (...)
    		{
    			LocalFree(msg);
    			throw;
    		}
    	}
    	return runtime_error(temp.str());
    }
    
    // um restlichen Buffer noch zu senden, falls send eher aufhört zu senden 
    void SendAll(int socket, const char* const buf, const int size)
    {
    	int bytesSent = 0;	// Anzahl Bytes, die bereits vom Buffer gesendet wurden
    	do 
    	{
    		int result = send(socket, buf + bytesSent, size - bytesSent, 0);
    		if (result < 0)
    		{
    			throw CreateSocketError();
    		}
    		bytesSent += result;
    	} while (bytesSent < size);
    }
    
    // liest eine Zeile des Socket in Stringstream (HTTP-Protokoll sendet zeilenweise)
    void GetLine(int socket, stringstream &line)
    {
    	// byteweise von Socket lesen, bis Zeilenumbruch auftritt
    	for (char c; recv(socket, &c, 1, 0) > 0; line << c)
    	{
    		if (c == '\n')
    		{
    			return;
    		}
    	}
    	throw CreateSocketError();	// wenn recv < 0 || = 0 ist, 
    }
    
    int main()
    {
    	WSADATA w;
    	// man will Zugriff auf Winsock-Lib haben
    	if (int result = WSAStartup(MAKEWORD(2,2), &w) != 0)
    	{
    		cout << "Winsock 2 konnte nicht gestartet werden! Error: " << result << endl;
    		return 1;
    	}
    	hostent *phe = gethostbyname("www.kernel.org");
    	if (phe == NULL)
    	{
    		cout << "Host konnte nicht aufgeloest werden!\n";
    		return 1;
    	}
    	if (phe->h_addrtype != AF_INET)
    	{
    		cout << "ungueltiger Adress-Typ!\n";
    		return 1;
    	}
    	if (phe->h_length != 4)
    	{
    		cout << "Ungueltiger IP-Typ!\n";
    		return 1;
    	}
    
    	SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    	if (Socket == -1)
    	{
    		cout << "Socket konnte nicht erstellt werden!\n";
    		return 1;
    	}
    
    	sockaddr_in service;
    	service.sin_family = AF_INET;	// für IPv4
    	service.sin_port = htons(80);	// Port 80 nutzt HTTP
    
    	// Iterator
    	char **p = phe->h_addr_list;	// p mit 1. Listenelement initialisieren
    	int result;						// Ergebnis von connect
    	do 
    	{
    		// Liste zu Ende ?
    		if (*p == NULL)
    		{
    			cout << "Verbindung fehlgeschlagen!\n";
    			return 1;
    		}
    		service.sin_addr.s_addr = *reinterpret_cast<unsigned long*>(*p);
    		++p;
    		result = connect(Socket, reinterpret_cast<sockaddr*>(&service), sizeof(service));
    
    	} while (result == -1);
    
    	cout << "Verbindung erfolgreich!\n";
    	const string request = "GET /faq/index.html HTTP/1.1\r\nHost: www.kernel.org\r\nConnection: close\r\n\r\n";
    
    	try
    	{
    		SendAll((int)Socket, request.c_str(), (int)request.size());
    		int code = 100;		// 100 = continue
    		string protokoll;
    		stringstream firstLine;
    		while (code == 100)
    		{
    			GetLine((int)Socket, firstLine);
    			firstLine >> protokoll;
    			firstLine >> code;
    			if (code == 100)
    			{
    				GetLine((int)Socket, firstLine);	// leere Zeile nach continue ignorieren
    			}
    		}
    		cout << "Protokoll: " << protokoll << endl;
    		if (code != 200)
    		{
    			firstLine.ignore();
    			string msg;
    			getline(firstLine, msg);
    			cout << "Error #" << code << " - " << msg << endl;
    			return 0;
    		}
    
    		bool chunked = false;		// wurde Transfer-Encoding: chunked angegeben ?
    		const int noSizeGiven = -1;
    		int size = noSizeGiven;		// speichert übergebene Dateigröße
    
    		while (true)
    		{
    			stringstream sstream;
    			GetLine((int)Socket, sstream);
    			if (sstream.str() == "\r")		// Header zu Ende
    			{
    				break;
    			}
    			string left;
    			sstream >> left;
    			sstream.ignore();		// Leerzeichen ignorieren
    
    			if (left == "Content-Length:")
    			{
    				sstream >> size;
    			}
    			if (left == "Transfer-Encoding:")
    			{
    				string transferEncoding;
    				sstream >> transferEncoding;
    				if (transferEncoding == "chunked")
    				{
    					chunked = true;
    				}
    			}
    		}
    
    		fstream out("faq.html", ios::binary|ios::out);
    		if (!out)
    		{
    			cout << "Could not create File!" << endl;
    			return 1;
    		}
    
    		int recvSize = 0;		// empfangene Bytes insgesamt
    		char buffer[1024];
    		int bytesRecv = -1;		// empfangene Bytes des letzten recv
    
    		if (size != noSizeGiven)	// wenn Größe über Content-Length gegeben wurde
    		{
    			cout << "0%";
    			while (recvSize < size)
    			{
    				if (bytesRecv = recv(Socket, buffer, sizeof(buffer), 0) <= 0)
    				{
    					throw CreateSocketError();
    				}
    				// empfange Anzahl an Bytes zu Gesamtanzahl addieren und Buffer in Datei schreiben
    				recvSize += bytesRecv;
    				out.write(buffer, bytesRecv);
    				cout << "\r" << recvSize * 100 / size << "%" << flush;	// mit \r an Anfang der Zeile springen
    			}
    		}
    		else
    		{
    			if (!chunked)
    			{
    				cout << "Downloading... (Unknown FileSize)" << endl;
    				while (bytesRecv != 0)
    				{
    					if (bytesRecv = recv(Socket, buffer, sizeof(buffer), 0) < 0)
    					{
    						throw CreateSocketError();
    					}
    					out.write(buffer, bytesRecv);
    				}
    			}
    			else
    			{
    				cout << "Donwloading... (Chunked)" << endl;
    				while (true)
    				{
    					stringstream sstream;
    					GetLine((int)Socket, sstream);
    					int chunkSize = -1;
    					sstream >> hex >> chunkSize;	// Größe des nächsten Parts einlesen
    					if (chunkSize <= 0)
    					{
    						break;
    					}
    					cout << "Downloading Part (" << chunkSize << " Bytes)..." << endl;
    					recvSize = 0;					// vor jeder Schleife wieder auf 0 setzen
    					while (recvSize < chunkSize)
    					{
    						int bytesToRecv = chunkSize - recvSize;
    						// an recv als Größe entweder sizeof(buf) oder aber bytesToRecv übergeben, wenn nur noch ein kleines Stück empfangen werden muss 
    						if (bytesRecv = recv(Socket, buffer, bytesToRecv > sizeof(buffer) ? sizeof(buffer) : bytesToRecv, 0) <= 0)
    						{
    							throw CreateSocketError();
    						}
    						recvSize += bytesRecv;
    						out.write(buffer, bytesRecv);
    						cout << "\r" << recvSize * 100 / chunkSize << "%" << flush;
    					}
    					cout << endl;
    					for (int i = 0; i < 2; ++i)
    					{
    						char temp;
    						recv(Socket, &temp, 1, 0);
    					}
    				}
    			}
    		}
    		cout << endl << "Finished!" << endl;
    	}
    	catch (exception &e)
    	{
    		cout << endl;
    		cerr << e.what() << endl;
    	}
    
    	closesocket(Socket);
    
    	cin.get();
    	return 0;
    }
    

    eben derselbe

    -----EDIT-----

    gelöst, muss jeweils so heißen:

    if ((bytesRecv = recv(Socket, buffer, sizeof(buffer), 0)) <= 0)
    

    Klammern übersehen 😉

    thx
    mfg



  • Hallo zusammen
    ist es hiermit auch möglich normale datein wie z.b. Zip Dateien zu downloaden.
    Und wenn nicht könnte mir dann evtl. jemanden sagen wie ich da vorgehen muss.

    Hab mir so ein ähnliches programm geschrieben aber kann irgendwie keine zip,exe usw. Dateien downloaden bekomm dann immer nen Fehler vom Server das die Datei nicht gefunden wurde.



  • Takti schrieb:

    Hallo zusammen
    ist es hiermit auch möglich normale datein wie z.b. Zip Dateien zu downloaden.
    Und wenn nicht könnte mir dann evtl. jemanden sagen wie ich da vorgehen muss.

    Ja, ist damit möglich. Wobei ich eher eine Library wie libcurl (http://curl.haxx.se/ ) nehmen würde.



  • Hallo
    Ich hab ma ne Frage. Hatt jmd vllt ein Tutorial das genau das Gegenteil macht sprich einen Server??



  • wie müsste man den code jetzt erweitern damit das auch mit proxies funktioniert?



  • Hallo, ich benutze Microsoft Visual Studio und habe Standard C/C++ Kenntnisse, jedoch komme einfach nicht an diesen Linker Fehlermeldungen vorbei:

    Fehler 2 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp__connect@12" in Funktion "_main". main.obj
    Fehler 3 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp__inet_addr@4" in Funktion "_main". main.obj
    Fehler 4 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp__htons@4" in Funktion "_main". main.obj
    Fehler 5 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp__socket@12" in Funktion "_main". main.obj
    Fehler 6 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp__WSAStartup@8" in Funktion "_main". main.obj
    Fehler 7 fatal error LNK1120: 6 nicht aufgelöste externe Verweise. C:\Users\Jan\msvc\Sockets\Debug\Sockets.exe

    Mein Code sieht so aus:

    #include <iostream>
    #include <winsock2.h>
    using namespace std;
    
    #define IP "79.233.22.28"
    #define PORT 80
    
    int main() {
    	WSADATA wsa;
    	int s;
    	sockaddr_in service;
    	int result;
    
    	if(result = WSAStartup(MAKEWORD(2,2), &wsa) != 0) {
    		cout << "WinSock Library couldn't be loaded!" << endl;
    		cout << "Error: " << result << endl;
    		return 1;
    	}
    
    	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
    	if(s == -1) {
    		cout << "Socket couldn't be set up!" << endl;
    		return 1;
    	}
    
    	service.sin_family = AF_INET;
    	service.sin_port = htons(PORT);
    	service.sin_addr.s_addr = inet_addr(IP);
    	result = connect(s, reinterpret_cast<sockaddr*>(&service), sizeof(service));
    
    	if(result == -1) {
    		cout << "Connection couldn't be established!" << endl;
    		return 1;
    	}
    	cout << "Connection established!" << endl;
    	closesocket(s);
    }
    

    Kann mir damit jemand weiterhelfen?
    Vielen Dank schon mal im voraus!



  • Sollten Sie Nutzer der MS VisualC++ IDE sein, müssen Sie die WS2_32.lib Bibliothek dem Linker bekannt geben. Dazu gehen Sie unter Projekt->Eigenschaften->Linker und tragen, wie im Screenshot zu sehen, die Library unter "Zusätzliche Abhängigkeiten" ein:

    http://www.c-plusplus.net/magazin/bilder/sockets_und_das_http-protokoll/03.png



  • Danke für den Tipp!



  • Hallo,

    ich connecte zu einer Website und kann mit SendAll eine Request machen und mit GetLine das Ergebniss auslesen. Die erste Request klappt. Wenn ich nochmals das gleiche Sende mit SendAll erhalte ich eine Leere Antwort. Beim dritten Versuch erhalte ich schlieslich beim Senden den Error Code 10053.

    Muss ich für jeden neuen Http-Request nochmals den socket closen und connecten?

    string request = "HEAD /index.php HTTP/1.1\r\nHost: www.google.de \r\n\r\n";
    std::stringstream line;
    SendAll(socket, request.c_str(), request.size());
    GetLine(socket, line);
    std::cout << line.str() << std::endl //klappt
    
    SendAll(socket, request.c_str(), request.size());
    GetLine(socket, line);
    std::cout << line.str() << std::endl; //leere Antowrt
    
    SendAll(socket, request.c_str(), request.size()); //fehler beim senden
    GetLine(socket, line);
    std::cout << line.str() << std::endl; 
    
    void SendAll(int socket, const char* const buf, const int size)
    {
        int bytesSent = 0; // Anzahl Bytes die wir bereits vom Buffer gesendet haben
        do
        {
            int result = send(socket, buf + bytesSent, size - bytesSent, 0);
            if(result < 0) // Wenn send einen Wert < 0 zurück gibt deutet dies auf einen Fehler hin.
            {
    			std::cout << WSAGetLastError();
            }
            bytesSent += result;
        } while(bytesSent < size);
    }
    
    // Liest eine Zeile des Sockets in einen stringstream
    void GetLine(int socket, std::stringstream& line)
    {
        for(char c; recv(socket, &c, sizeof(c), 0) > 0; line << c)
        {
    
        }
       // throw CreateSocketError();
    return;
    }
    

    Hier der komplette Code, der eigentlich dreimal die Zeit messen soll.

    // socket.cpp: Hauptprojektdatei.
    #include "stdafx.h"
    #include <iostream>
    #include <time.h>
    #include <fstream>
    #include <stdexcept> // runtime_error
    #include <sstream>
    #include <winsock2.h>
    
    void SendAll(int socket, const char* const buf, const int size)
    {
        int bytesSent = 0; // Anzahl Bytes die wir bereits vom Buffer gesendet haben
        do
        {
            int result = send(socket, buf + bytesSent, size - bytesSent, 0);
            if(result < 0) // Wenn send einen Wert < 0 zurück gibt deutet dies auf einen Fehler hin.
            {
    			std::cout << WSAGetLastError();
            }
            bytesSent += result;
        } while(bytesSent < size);
    }
    
    // Liest eine Zeile des Sockets in einen stringstream
    void GetLine(int socket, std::stringstream& line)
    {
        for(char c; recv(socket, &c, sizeof(c), 0) > 0; line << c)
        {
    		if (c=='\n'){
    			return;}
        }
       // throw CreateSocketError();
    return;
    }
    
    float StopTime(int socket, std::string request){
    	float sec;
        clock_t tvor;
    	tvor=clock();
        SendAll(socket, request.c_str(), request.size());
    	std::stringstream line;
    		GetLine(socket, line);
    		std::cout << line.str() << std::endl;
    
    	sec=(static_cast<float>(clock()-tvor))/CLOCKS_PER_SEC;
    	return sec;
    }
    
    int main()
    {
        using namespace std;
    
    #ifndef linux
        WSADATA w;
        if(int result = WSAStartup(MAKEWORD(2,2), &w) != 0)
        {
            cout << "Winsock 2 konnte nicht gestartet werden! Error #" << result << endl;
            return 1;
        }
    #endif
    
        hostent* phe = gethostbyname("www.google.de");
    
        if(phe == NULL)
        {
            cout << "Host konnte nicht aufgeloest werden!" << endl;
            return 1;
        }
    
        if(phe->h_addrtype != AF_INET)
        {
            cout << "Ungueltiger Adresstyp!" << endl;
            return 1;
        }
    
        if(phe->h_length != 4)
        {
            cout << "Ungueltiger IP-Typ!" << endl;
            return 1;
        }
    
        int Socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(Socket == -1)
        {
            cout << "Socket konnte nicht erstellt werden!" << endl;
            return 1;
        }
    
        sockaddr_in service;
        service.sin_family = AF_INET;
        service.sin_port = htons(80); // Das HTTP-Protokoll benutzt Port 80
    
        char** p = phe->h_addr_list; // p mit erstem Listenelement initialisieren
        int result; // Ergebnis von connect
        do
        {
            if(*p == NULL) // Ende der Liste
            {
                cout << "Verbindung fehlgschlagen!" << endl;
                return 1;
            }
    
            service.sin_addr.s_addr = *reinterpret_cast<unsigned long*>(*p);
            ++p;
            result = connect(Socket, reinterpret_cast<sockaddr*>(&service), sizeof(service));
        }
        while(result == -1);
    
        cout << "Verbindung erfolgreich!" << endl;
    	std::cin.ignore();
        string request = "HEAD /index.php HTTP/1.1\r\nHost: www.google.de \r\n\r\n";
        string ein;
    		cout << StopTime(Socket,request);
    		cin.ignore()
    		cout << StopTime(Socket,request);
    		cin.ignore();
    		cout << StopTime(Socket,request);
    		cin.ignore();
        closesocket(Socket);
    }
    


  • Hallo allerseits! Ich bin momentan noch auf der ersten Seite dieses Threads und arbeite mich da so langsam durch. Habe aber folgendes Problem:

    Bei dem "Selfmade nslookup" funktioniert bei mir die Anzeige der Aliases nicht. Wenn ich das nslookup des Terminals benutze, erhalte ich Aliases, die ich mit dem Code aus diesem Thread nicht bekomme (scheine mit dem hiesigen Code GAR KEINE Aliases angezeigt zu bekommen).

    Dazu sei noch gesagt, dass ich das ganze für den linuxartigen Teil des Codes mit g++ unter Cygwin kompilieren lasse.

    Weiß jemand Rat?



  • hallo,
    hab den quelltext mit vielen Seiten probiert, aber eine Seite funktioniert nicht.
    www.die-staemme.de
    kann das jemand anderes mal ausprobieren? Da kommt immer Verbingung erfolgreich und dann nichts mehr... Warum ist das so? Wie kann das umgehen?



  • Vielleicht irgendein Bot Schutz ?

    "Schutz gegen Cheater"



  • bot schrieb:

    Vielleicht irgendein Bot Schutz ?

    "Schutz gegen Cheater"

    Ja, eventuell wird der User-Agent im Header überprüft oder ähnliches, so das Computerprogramme ausgeschlossen werden. Könnte mir das sehr gut vorstellen.



  • Wenn ich die ganze Server-Response in einem std::string x habe, wie extrahiere ich draus den header?



  • jan1985 schrieb:

    Hallo, ich benutze Microsoft Visual Studio und habe Standard C/C++ Kenntnisse, jedoch komme einfach nicht an diesen Linker Fehlermeldungen vorbei:

    Fehler 2 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp__connect@12" in Funktion "_main". main.obj
    Fehler 3 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp__inet_addr@4" in Funktion "_main". main.obj
    Fehler 4 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp__htons@4" in Funktion "_main". main.obj
    Fehler 5 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp__socket@12" in Funktion "_main". main.obj
    Fehler 6 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp__WSAStartup@8" in Funktion "_main". main.obj
    Fehler 7 fatal error LNK1120: 6 nicht aufgelöste externe Verweise. C:\Users\Jan\msvc\Sockets\Debug\Sockets.exe

    Mein Code sieht so aus:

    #include <iostream>
    #include <winsock2.h>
    using namespace std;
    
    #define IP "79.233.22.28"
    #define PORT 80
    
    int main() {
    	WSADATA wsa;
    	int s;
    	sockaddr_in service;
    	int result;
    
    	if(result = WSAStartup(MAKEWORD(2,2), &wsa) != 0) {
    		cout << "WinSock Library couldn't be loaded!" << endl;
    		cout << "Error: " << result << endl;
    		return 1;
    	}
    
    	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
    	if(s == -1) {
    		cout << "Socket couldn't be set up!" << endl;
    		return 1;
    	}
    
    	service.sin_family = AF_INET;
    	service.sin_port = htons(PORT);
    	service.sin_addr.s_addr = inet_addr(IP);
    	result = connect(s, reinterpret_cast<sockaddr*>(&service), sizeof(service));
    
    	if(result == -1) {
    		cout << "Connection couldn't be established!" << endl;
    		return 1;
    	}
    	cout << "Connection established!" << endl;
    	closesocket(s);
    }
    

    Kann mir damit jemand weiterhelfen?
    Vielen Dank schon mal im voraus!



  • Entsprechende lib einbinden!
    wsock32.lib oder ws2_32.lib - hab vergessen wie die heisst.



  • EOP schrieb:

    Entsprechende lib einbinden!
    wsock32.lib oder ws2_32.lib - hab vergessen wie die heisst.

    Letztere.



  • Artchi schrieb:

    Die Kompressionsrate des JPEGs ist nur zu hoch. Man kann deshalb fast nichts erkennen. Ansonst hat das Bild irgendwie einen gewissen Charme. 😃

    Für eine derartige Grafik ist JPEG völlig ungeeignet. Am besten PNG.



  • Hab nochmal nachgeschaut, es ist schon, wie es sich gehört, ein PNG. 😃



  • Weiß jemand warum bei mir die recv Funktion nicht ganz geht? Also besser gesagt will ich das das er die While schleife verlässt wenn ein bestimmtes Zeichen im String vorliegt... das letzte Zeichen beim empfangen endet mit "]", dennoch läuft die schleife weiter auch wenn ich (c == ']') in den Funktion schreibe. Die Text Datei wird ohne Zeichen einfach weiter gefüllt da recv nicht gestoppt wird. Weiß jemand woran das liegt oder wie ich am besten aus der while schleife raus komme wenn das letzte zeichen ein "]" ist, so das mein Programm nach empfangen aller Daten weiter laufen kann?


Anmelden zum Antworten