Sockets: String an welcher Stelle auswerten.



  • Ich bin mal wieder oder besser gesagt immer noch beim proggen an einem Netzwerkspiel. Meine Netzwerkklasse habe ich mit Unterstützung von Herrn Zerbst aus dem Buch "3D-Spieleprogrammierung" erstellt. Ich schreibe den empfangenen String also quasi in eine Queue, die ich später einfach blos wieder auslese.
    Desweiteren fange ich die Nachrichten mit eigenen Windows-Messages ab alá WSAAsyncSelect.
    Da ich in dem aktuellen Programm nicht auf DirectX-Elemente zurückgreife, sondern nur rein mit WINApi arbeite stellt sich für mich eine Umsetzungsfrage, die meiner Meinung nach am besten jemand mit der gleichen Erfahrung beantworten könnte *g*.

    Version 1 meines Programmes und die aktuelle:

    Nachrichtenschleife mit GetMessage

    while(GetMessage(&message, NULL, 0, 0)) 
    	{
    		TranslateMessage(&message);
    		DispatchMessage(&message);
    	}
    

    Auswetung der gesendeten Strings

    case WM_RDCLIENT:
    		{
    			WORD wEvent = LOWORD(lParam);
    
    			switch(wEvent)
    			{
    				case FD_READ:
    				{
    					g_oMain->oSocketClient.onReceive(wParam, Main::callbackReceiveString)
    				} break;
    
    				case FD_CLOSE:
    				{
    					g_oMain->oSocketClient.onDisconnect(wParam)
    				} break;
    			}
    		} break;
    
    ...
    
    // Funktion ist static
    bool Main::callbackReceiveString(SOCKET &soc, std::string &str)
    {
    	g_oMain->setReceivedBytes(str);
    
    	return true;
    }
    
    void Main::setReceivedBytes(std::string bufNetwork)
    {
    	// Auswertung des Strings
    }
    

    Die alte Version, wovon ich natürlich kein Backup gemacht habe 😃

    while(!ende)
    {
    	while(PeekMessage(&message, NULL, 0, 0)) 
    	{
    		TranslateMessage(&message);
    		DispatchMessage(&message);
    	}
    
    	// Queue wird dann direkt in der folgenden Funktion ausgelesen
    	g_oMain->setReceivedBytes();
    }
    

    Bei der 2. Version habe ich ohne Callbackfunktionen gearbeitet.

    Zu Hause habe ich nur einen Rechner und teste über localhost. Hierbei habe ich 2 Fenster gleichzeitig auf uns switche mit Alt+Tab. Version 2 sorgte dafür, dass es zu fehlerhaften Anzeigen kam. Allerdings lief es im Netzwerk bei mir auf Arbeit doch recht vernünftig.
    Version 1 lief zu Hause prima auf Arbeit allerdings bereits bei Spielstart fehlerhafte Anzeige.

    Viel geschrieben und nur ne kurze Frage. Sollte man lieber GetMessage oder lieber PeekMessage verwenden? Gibt es Erfahrungswerte bei solchen Dingen?
    Anhand meiner Log-Dateien kann ich sagen, dass der String richtig ankommt.



  • Bei einem Spiel solltest du vllt eher die nicht-blockende variante nutzen^^... PM_REMOVE nicht vergessen :P...



  • Hi,..

    meine lieblingsvariante ist einen seperaten thread mit einer "bRun" konditionierten endlosschleife welche auf ein netzwerkevent wartet zu nutzen.

    Leider habe ich jetzt gerade kein Konkretes Beispiel

    volatile bRun; //somit auch aus einem anderen thread auf false setzbar
    
    ... ThreadProc(....)
    {
    while(bRun)
    {
    Sleep(1);  //haue ich bei "endlosschleifen" threads immer rein um bei leerlauf 
               //den prozessor zu schonen
    
    status = WaitForMultipleObjects(....
    
    switch(status)
      {
       case CONNECT:....
       case CLOSE:.....
       case RECV:....
       case SEND:.....
       default:...
      }
    }
    
    }
    

    Sei gegrüßt



  • Sodala etsala,

    ich will ja auch Rueckmeldung zu meinem umgesetzten geben, damit andere auch was davon haben. Erstmal hab ich mich fuer PeekMessage entschieden. Macht ja auch irgendwie Sinn, was Inc sagt. Nichtblockierend ist da fuer ein Spiel durchaus besser.
    Des weiteren hab ich das Sleep(1) von Zeusosc geklaut. Durchaus keine schlechte Idee.
    Das eigentliche Problem mit den fehlerhaften Anzeigen kam durch das empfangen der Pakete selbst zu stande. Diese wurden so schnell gesendet, dass ich beim empfangen das eine vom anderen nicht mehr auseinanderhalten.
    Durch einen Protokollparser mit Header, der die Laenge des Paketes enthaelt, hab ich das Problem dann loesen koennen. Nun ruckelt es zwar bei den Clients, aber das ist eine andere Geschichte.



  • Die Loesung fuer das ruckeln bei den Clients wurde nun auch geloest.
    Folgende Zeilen direkt nach dem erstellen des Sockets einfuegen.

    int flag = 1;
    if(setsockopt(m_sock, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof(int)) < 0)
    {
    	return false;
    }
    

    Nun steht auch Netzwerktechnisch einem guten WinAPI-Spiel nichts mehr im Wege 😃

    thanks Max0r


Log in to reply