Eingenen ServerBrowser schreiben



  • Hallo,
    ich habe ein favoriten-Programm für das Spiel Wolfenstein: Enemy Territory geschrieben, funzt und so.
    Nun habe ich ne frage wie kann ich über die IP-Adresse und ich denke mal
    via socket eine Verbindung zum Server herstellen und z.B. auslesen wieviele Spieler drauf sind?
    Ich hoffe ihr versteht was ich meine...

    MfG agent_x



  • Naja, du schreibst ein Programm, das sich mit dem Serverrechner verbindet (das erledigt die Socket-lib deiner wahl, z.B. winsock, boost.asio oder eine andere). Dann musst du noch wissen, wie du dort den Spielserver ansprechen kannst (dazu findest du die nötigen Informationen eher in den entsprechenden Spieleforen als hier). Am Ende wertest du die Antwort vom Server aus und gibst sie irgendwie auf dem Bildschirm aus.

    Deine Frage war so grob und ungenau gestellt, dass die Antwort eben auch nur so grob und ungenau ausfallen konnte. Wen du spezielle Probleme bei einzelnen Schritten hast helfen wir natürlich gerne weiter, vorausgesetzt es handelt sich um Probleme im Standard-C++ Bereich.



  • Auf http://int64.org/docs/gamestat-protocols/ bzw. direkt http://int64.org/docs/gamestat-protocols/quake3.html siehst du wie deine Anfrage (Query) aussehen muss und wie deine Antwort (Response) ungefähr aussehen wird.

    Du kannst aber natürlich auch gleich die fertige Lib http://int64.org/projects/gamestat-library nehmen.



  • Also ich habe dieses Tutorial schon mehrere male durch gelesen: http://www.c-worker.ch/tuts/wstut_op.php aber
    iwie verstehe ich das nicht könntet ihr mir helfen eine Verbindung per winsocket
    aufzubauen?
    Und danke für diesen sehr nützlichen Link, Tobiking2



  • agent_x schrieb:

    Also ich habe dieses Tutorial schon mehrere male durch gelesen: http://www.c-worker.ch/tuts/wstut_op.php aber
    iwie verstehe ich das nicht könntet ihr mir helfen eine Verbindung per winsocket
    aufzubauen?
    Und danke für diesen sehr nützlichen Link, Tobiking2

    Klar.
    Die Frage ist nur: wo liegt dein Problem und warum nimmst du nicht einfach die Bibliothek die Tobiking2 verlinkt hat?



  • blub² schrieb:

    warum nimmst du nicht einfach die Bibliothek die Tobiking2 verlinkt hat?

    weil ich gerne wissen möchte wie man eine winsocket verbindung aufbaut,
    und wie der Datenaustausch erfolgt...(ich bin halt neugierig :])

    Es geht schon beim starten der WSA Funktion los...
    Wie erkenne ich z.B. die benötigte Version der winsockets?

    PS.: Das mit dem Protocol verstehe ich aber das mit winsocket iwie nicht....



  • agent_x schrieb:

    Es geht schon beim starten der WSA Funktion los...
    Wie erkenne ich z.B. die benötigte Version der winsockets?

    Da neue Winsock Versionen nur Funktionen hinzufügen solltest du ohne Probleme die kleinste Version nehmen die all das kann was du benötigst. Das sollte seit 1.2 schon der Fall sein. Da aber Winsock 2.0 seit Windows 98/2000 fest im Betriebsytem ist kannst du auch ohne Probleme die 2.0 nehmen.



  • Also ich habe jetzt ein paar Tage versucht die verbindung zu einem Server
    herzustellen, doch ohne Erfolg....
    Könntet ihr mir vielleicht sagen wie ich winsock in Borland C++ 6
    benutzen kann?



  • Haha,
    ich habe es mit WinSock hingekiegt eine Verbindung auf meinen WebServer herzustellen!
    Jetzt zu meiner vorherigen Frage: was muss ich an den GameServer senden
    um einen Status zu empfangen?

    Hier mein Code:

    WSADATA WSAData;
       WSAStartup(MAKEWORD(2,0), &WSAData);
       SOCKET sock;
       SOCKADDR_IN sin;
       sock = socket(AF_INET, SOCK_STREAM, 0);
       char buffer[2048];
       string got;
       string v;
    
       string request = "GET /xxxxxxx/xxx/version.dat HTTP/1.1\r\n";
       request += "Host: xxxxxxx.xxxxxxx.xxx\r\n";
       request += "User-Agent: Mozilla Firefox 3.5.3\r\n";
       request += "Accept: */*\r\n";
       request += "Referer: http://serverfavorite.de.hm\r\n";
       request += "\r\n";
    
            sin.sin_addr.s_addr = inet_addr("xxx.xx.xx.xxx");
            sin.sin_family = AF_INET;
            sin.sin_port = htons(80);
    
            if(connect(sock, (SOCKADDR *)&sin, sizeof(sin)) == SOCKET_ERROR) {
                    ShowMessage("Version check failed!\n Can not connect to server.");}
            else {
                    strcpy(buffer, request.c_str());
                    send(sock, buffer, request.size() + 1, 0);
                    while (recv(sock, buffer, sizeof(buffer), 0) != 0) {
                            got = buffer;
                            v = got.replace(0, got.find("= ") + 2, "");}}
    
            closesocket(sock);
            WSACleanup();
    

    Wenn ich diesen Befehl ausführe so wird der in halt der
    Datei(in dem Fall 0.90) ausgegeben, aber mit irgend so einem komischem Zeichen
    hinten dran! Wieso?
    Und noch eine Frage wie kann ich z.B. eine exe mit HTTP downloaden?
    Ich habe mir diesen Eintrag angeguck: http://c-plusplus.net/forum/viewtopic-var-t-is-219181-and-highlight-is-http+download.html
    , aber ich verstehe den code nicht ganz.... Danke schon mal jetzt für eure Hilfe 🙂

    MfG agent_x



  • http://c-plusplus.net/forum/viewtopic-var-t-is-169861.html

    Netzwerkprogrammierung erfordert einiges an Wissen...



  • strcpy(buffer, request.c_str()); 
                    send(sock, buffer, request.size() + 1, 0); 
                    while (recv(sock, buffer, sizeof(buffer), 0) != 0) { 
                            got = buffer; 
                            v = got.replace(0, got.find("= ") + 2, "");}}
    

    ist unnötig, fehleranfällig und zum teil auch einfach glück, dass es funktioniert...
    unnötig: warum kopierst du erst?
    fehleranfällig: du testest nirgendwo auf request.size() < sizeof(buffer)
    wobei ich direkt wieder sizeof buffer durch ne konstante ersetzen würde(die ich auch bei der array-deklaration verwenden würde) - aber das ist vrmtl geschmackssache...
    glück: send hat nur <rückgabewert> anzahl an bytes senden können - das muss nicht unbedingt alles gewesen sein
    send kann auch SOCKET_ERROR zurückgeben, wenn ich mich recht entsinne - z.bsp., wenn mit diesem aufruf noch nicht alles empfangen wurde - aber imho auch bei "richtigen" fehlern.
    got.find("= ") kann auch npos liefern("= " existiert nicht nach position {letzter parameter(= size_type(/*0*/) )}) und damit würdest du ne length_error-exception oder wie auch immer die heißt bekommen...

    bb

    PS: Can not gibt es zwar im englischen, aber imho ist es in diesem kontext nicht nur extrem ungebräuchlich sondern falsch



  • Wenn ich

    void GetLine(int socket, std::stringstream& line) {
        for(char c; recv(socket, &c, 1, 0) > 0; line << c) {
            if(c == '\n') {
                return;}}
    }
    

    versuche in meinen code einzubauen kommt bbei mir nix!!!



  • ich sollte mal mitzählen, wie oft in letzter zeit ich was in dem forum hier über winsock-send + -recv geschrieben hab 😣

    #include <string>
    #include <windows.h>
    
    enum { BUF_LEN = 1024 };
    
    std::string receive(SOCKET socket)
    {
    	char buf[BUF_LEN];
    
    	std::string R;
    	int length;
    
    	for( ;; )
    	{
    		length = recv(socket, &buf[0], BUF_LEN, 0);
    
    		if(length == 0)
    		//	"connection gracefully closed" oder so was in der richtung sollte in der msdn stehen
    		if(length == SOCKET_ERROR)
    		{
    			if(GetLastError() != WSAEMSGSIZE)
    				throw std::runtime_error("failure at receive");
    
    			R.append(&buf[0], &buf[BUF_LEN]);
    			continue;
    		}
    	}
    
    	R.append(&buf[0], &buf[length]);
    	return R;
    }
    

    wenn du nur das stück bis zum ersten zeilenumbruch haben möchtest, dann würde ich das an deiner stelle später machen... (std::string.find('\n'));
    aber dazu würd ich noch sagen, dass es nich die allerbeste idee ist, zeilenumbrüche zum trennen zu verwenden(weil die je nach system verschieden sind "\r\n", "\n", ...

    falls du fragen hast:
    http://msdn.microsoft.com/en-us/library/ms740121(VS.85).aspx
    lesen und danach kannste immernoch fragen

    bb



  • #include <iostream>
    #include <fstream>
    #include <winsock2.h>
        using namespace std;
    
    enum {buflen = 1024};
    
    int main() {
      WSADATA WSAdata;
      WSAStartup(MAKEWORD(2,0), &WSAdata);
      SOCKET sock;
      SOCKADDR_IN sin;
      sock = socket(AF_INET, SOCK_STREAM, 0);
      string stream;
      char recvbuf[buflen];
      int recvbuflen = buflen;
      int got;
      int allinall = 0;
    
      string request = "GET /serverfavorite/files/ET/serverfavorite.exe HTTP/1.1\r\n";
      request += "HOST: xxxxxxx.xxxxxxx.xxx\r\n";
      request += "Connection: closed\r\n\r\n";
      sin.sin_family = AF_INET;
      sin.sin_addr.s_addr = inet_addr("xxx.xx.xx.xxx");
      sin.sin_port = htons(80);
    
        if(connect(sock, (SOCKADDR *)&sin, sizeof(sin)) == SOCKET_ERROR) {
            cout << "Konnte nicht mit dem server verbinden!\n";}
        else {
            cout << "Mit dem Server verbunden!\n";
            if(send(sock, request.c_str(), request.size() + 1, 0) == SOCKET_ERROR) {
                cout << "Konnte Anfrage nicht senden!\n";}
            else {
                cout << "Anfrage gesendet!\n";
                fstream f("test.exe", ios::binary | ios::out);
                if(!f) {
                    cout << "Konnte datei nicht erstellen!\n";}
                else {
                    cout << "Erstelle Datei.... ";}
                while((got = recv(sock, recvbuf, recvbuflen, 0)) > 0) {
                    if(got > 0) {
                        cout << "\r" << "Empfange.... (" << got << " Bytes)" << flush;}
                        f.write(recvbuf, got);
                        allinall += got;}
                cout << "\nFertig (" << allinall << " Bytes)\n";
                f.close();}}
    
        closesocket(sock);
        WSACleanup();
    
            return 0;
    }
    

    Mein neuer Code(nur zum testen), aber erfunzt nicht richtig... 😞
    er lädt alles runter.... schreibt die HTTP Header in die Datei, den Inhalt...
    Wenn ich aber am Ende die Header manuell entferne und versuche die Datei zustarten,
    geht es nicht...



  • int main() {
    }
    

    mein neuer code - funktioniert super...

    mal im erst - teil deinen code in paar fkt auf... ich hab dir doch nun schon eine gegeben, die du nutzen kannst...
    so was guck ich mir auf jeden fall jz in nächster zeit nicht an...

    bb



  • #include <stdexcept>
    #include <string>
    #include <winsock2.h>
    #include <windows.h>
    
    namespace sockets
    {
    	class http
    	{
    	private:
    		SOCKET sock;
    
    		static std::size_t counter;
    		enum { BUF_LEN = 1024 };
    
    		void connect(const std::string &ip)
    		{
    			SOCKADDR_IN sin;
    			sin.sin_family = AF_INET;
    			sin.sin_addr.s_addr = inet_addr(ip.c_str());
    			sin.sin_port = htons(80);
    
    			int error_code = ::connect(sock, (SOCKADDR *)&sin, sizeof(sin));
    			if(error_code == SOCKET_ERROR)
    			{
    				throw std::runtime_error("Cannot connect to " + ip);
    			}
    		}
    	public:
    		http()
    		:	sock(INVALID_SOCKET)
    		{
    			if(counter++ == 0)
    			{
    				WSADATA WSAdata;
    				WSAStartup(MAKEWORD(2,0), &WSAdata);
    			}
    
    			sock = socket(AF_INET, SOCK_STREAM, 0);
    			if(sock == INVALID_SOCKET)
    			{
    				throw std::runtime_error("Cannot create socket");
    			}
    		}
    
    		~http()
    		{
    		    closesocket(sock);
    
    			if(--counter > 0)
    				return;
    
    			WSACleanup();
    		}
    
    		void send(const std::string &ip, const std::string &request)
    		{
    			connect(ip);
    
    			int error_code = ::send(sock, request.c_str(), request.size()+1, 0);
    			if(error_code == SOCKET_ERROR)
    			{
    				throw std::runtime_error("Cannot send request");
    			}
    		}
    
    		std::string recv()
    		{
    			char buf[BUF_LEN];
    
    			std::string R;
    			for( ;; )
    			{
    				const int length = ::recv(sock, &buf[0], BUF_LEN, 0);
    
    				if(length == 0)
    				{//	hier ist auch ne andere behandlung denkbar
    					throw std::runtime_error("Connection closed");
    				}
    				else if(length == SOCKET_ERROR)
    				{
    					if(GetLastError() == WSAEMSGSIZE)
    					{
    						R.append(&buf[0], &buf[BUF_LEN]);
    						continue;
    					}
    
    				//	hier evtl noch auf unterschiedliche errorcodes unterschiedlich reagieren...
    					throw std::runtime_error("failure at receive");
    				}
    				else
    				{
    					R.append(&buf[0], &buf[length]);
    					break;
    				}
    			}
    
    			return R;
    		}
    	};
    
    	std::size_t http::counter = 0;
    }
    
    //Console - helper
    #include <iostream>
    void wait()
    {
    	std::cin.clear(); 
    	std::cin.ignore( std::cin.rdbuf()->in_avail());
    	std::cin.get();
    }
    
    //Request - helper
    std::string get_request()
    {//	evtl dynamisch erstellen!?
    	std::string request = "GET /serverfavorite/files/ET/serverfavorite.exe HTTP/1.1\r\n";
    	request += "HOST: xxxxxxx.xxxxxxx.xxx\r\n";
    	request += "Connection: closed\r\n\r\n";
    	return request;
    }
    
    #include <fstream>
    
    int main()
    {
    	try
    	{
    		sockets::http http_sock;
    		std::cout << "socket created" << std::endl;
    		http_sock.send("127.0.0.1", get_request());
    		std::cout << "request transmitted" << std::endl;
    		std::string received = http_sock.recv();
    		std::cout << "completly received" << std::endl;
    		std::fstream out("test.exe", std::ios::binary | std::ios::out);
    		out.write(received.c_str(), received.size());
    		std::cout << "saved the received (" << received.size() << " Byte)" << std::endl;
    	}
    	catch(const std::exception &e)
    	{
    		std::cout << e.what() << std::endl;
    	}
    
    	wait();
    }
    

    so in etwa sollte es funktionieren...
    evtl solltest du - falls es noch immer nicht funktioniert (was gut sein kann) mal ne bessere fehlerbeschreibung liefern bzw mal mit nem hexeditor die beiden dateien öffnen und vergleichen und sagen wo und wie sich diese unterscheiden...

    bb



  • Sorry, dass ich so lange nicht geantwortet habe...
    ---edit hat sich geklärt---


Anmelden zum Antworten