Winsock recv in eigenem SDL-Thread, Performance



  • Hallo,

    ich schreibe grade ein kleines Netzwerkspiel per OpenGL und SDL.

    Da recv eine blockierende Winsock-Funktion ist, habe ich für den Nachrichtenempfang eben einen eigenen Thread erstellt. So laufen immer 2 Dauerschleifen im Hintergrund (die main-Schleife zur Grafikdarstellung und die Schleife für recv, die auf Nachrichten wartet).

    Allerdings ist dadurch die CPU-Auslastung immer auf 100%, scheint nicht grade die eleganteste Art zu sein die Winsock-Nachrichten abzufangen.

    Wie könnte ich das Problem mit der blockierenden recv-Funktion besser lösen bzw. meine ReceiveMessages-Funktion verbessern? Nachrichten dürfen unter keinen Umständen verloren gehen, also kann ich auch kein Timeout für recv setzen. Bei select() mit Timeout habe ich auch Bedenken, dass Daten verloren gehen.

    Das hier ist die Funktion, die in einem eigenen SDL-Thread permanent im Hintergrund läuft:

    int ReceiveMessages(void *data)
    {
        char message_receive[10];
        char message_data[9];
        int i;
    
        printf("ReceiveMessages-Thread gestartet\n");
        while(running) //connection raus
        {
            if(recv(connection,message_receive,20,0)>0)
            {
                //printf("Nachricht von Client: %s (%i)\n",message_receive,strlen(message_receive));
                for(i=1;i<strlen(message_receive);i++)
                {
                    message_data[i-1]=message_receive[i];
                }
                message_data[i-1]='\0';
                if(message_receive[0]=='x') x_enemy=atoi(message_data);
            }
        }
        printf("ReceiveMessages-Thread gestoppt\n");
    }
    


  • Pack halt noch ein Sleep rein, wenn du Probleme damit hast, dass ein Spiel scheinbar 100% CPU-Auslastung hat (was im Übrigen normal ist).



  • lass dich doch einfach benachrichtigen wenn daten da sind:

    WSAAsyncSelect(socket, hwnd, MESSAGEID, FD_READ);
    


  • Ok, mit der Prozessorlast hast du recht, das war schlecht ausgedrückt. Anders gefragt: Ist diese Art des Multithreadings für ein schnelles Netzwerkspiel ok? Oder gibt es Möglichkeiten das Ganze performanter zu gestalten?



  • hellihjb schrieb:

    lass dich doch einfach benachrichtigen wenn daten da sind:

    WSAAsyncSelect(socket, hwnd, MESSAGEID, FD_READ);
    

    Ist kein Windowsprogramm, habe also auch keinen Windows-Handle!



  • select()



  • Select mit Timeout in der Hauptschleife anstelle von einem separaten Thread? Besteht da nicht die Gefahr, dass Daten flöten gehen?



  • Rastafarianism schrieb:

    Select mit Timeout in der Hauptschleife anstelle von einem separaten Thread? Besteht da nicht die Gefahr, dass Daten flöten gehen?

    nein eigentlich nicht, oder benutzt du udp oder ähnliches?



  • Nope, läuft über TCP. Dann versuch ich es mal per select() mit Timeout in der Hauptschleife, thanks 🙂



  • Wenn du an einem Netzwerk spiel bist, habe ich auch ne frage...

    Ich proge so nen Art Fight spiel. Zwei charas welche gegeneinander
    kampfen. vl kennt das noch jemand von den alten spiel konsolen.
    Nur ist meins Netzwerk faehig bzw. sollte.

    Nun habe ich mir gedanken gemacht, wie ich das am besten
    umsetzen kann.
    Eigentlich sind es ja Zwei Objekte (spirits). Den einen steuere ich und
    der zweite spirit wird von Computer gesteuert. Der PC bekommt
    aber die Steuerbefaehle von einem Socket.

    Beim anderen Player is es natuerlich gleich.
    Nun ist das Problem das es ein rundungsfehler geben kann wenn
    jemand zurueckspring. Dann waehre das spiel beiden orten nicht mehr synchron.
    Das koennte man umgehen wenn man die coods auch synchronisiert ergo
    ab und zu mal die positionen richtet bzw. abgleicht.

    Da aber beide gleichzeitig auf die Tasten hauen und der PC nicht beide
    spirits gleichzeitig berechnen kann, weiss ich ned was passiert.

    Nun habe ich zweifel an meiner Metode.
    Eine andere Idee welche ich gleichwieder verworfen habe war:
    alles passiert auf dem "server" und der Client (2er Player)
    bekommt nur das Bild "SDL_Surface" uebers netz.

    Hat da jemand schon erfahrungen damit gemacht,
    oder ne Technik Idee/vorschlag?



  • @xghost

    Ich hätte ne Idee, weiß aber nicht ob das so gut funktioniert.
    jeder PC berechnet alles für sich und schickt immer nur Position und den Schaden den er dem Gegner hinzufügt. Der Vorteil wäre: Die Kämpfer reagieren auf den Tastendruck genau, also ohne Verzögerung, und der spieler schlägt nicht vergebens auf eine "vergange" Position ein ohne Schaden zu ziehen. Der Nachteil wäre: Man kann nicht immer nachvollziehen wie der Gegner denn jetzt schaden gezogen hat. (außerdem lässt sich natürlich leicht cheaten)

    Ich hoffe man kann verstehen was ich meine.

    mfg.



  • Ja, aber das problem ist immer noch, das ich nur ein Prozessor habe
    und somit nur immer ein Chara berechnen kann und dann den zweiten.

    Ich frage mich grad, ob das bei den heutigen PC ueberhaubt noch eine
    rolle spielt. Die rechnen ja so schnell das ich loker 40 frames in
    der sekunde hinbekomme mit berechnung.

    Was auch gut moeglich ist, das ich mir sorgen um nix mache.
    Ich proge es mal und sehe was dabei rauskommt.

    Ich muss sowieso noch hinbekommen mit blender ein chara zu erstellen 😞

    Mal sehen,
    Gg



  • Moin.

    Also, der Server läuft mit select() wunderbar, der zweite Thread ist rausgeflogen! Jetzt wollte ich die Daten, die der Server dem Client schickt beim Client auch per select() abholen, aber leider klappt das nicht.

    FD_ISSET(connection,&fdSet) wird nie wahr, obwohl der Server Daten zum Client schickt.

    Hier der Client-Code (connection ist der Socket, der sich per connect() zum Server verbunden hat):

    if(connection)
                {
        		    FD_ZERO(&fdSet);
                    FD_SET(connection,&fdSet);
    
                    rc=select(0,&fdSet,NULL,NULL,&time_delay);
                    if(rc==SOCKET_ERROR)
                    {
                        printf("Select Fehler: %s\n",WSAGetLastError());
                        running=0;
                    }
                    if(FD_ISSET(connection,&fdSet))
                    {
                        printf("AUFRUF RECV");
                        rc=recv(connection,message_receive,256,0);
    
                        if(rc==0)
                        {
                            printf("Server hat die Verbindung geschlossen\n");
                            running=0;
                        }
                        else if(rc==SOCKET_ERROR)
                        {
                            printf("RECV Fehler\n");
                            running=0;
                        }
                        else
                        {
                            message_receive[rc]='\0';
                            printf("RECEIVE: %s\n",message_receive);
                            for(i=1;i<strlen(message_receive);i++)
                            {
                                message_data[i-1]=message_receive[i];
                            }
                            message_data[i-1]='\0';
                            if(message_receive[0]=='x') x_enemy=atoi(message_data);
        		        }
                    }  
                }
    

    edit:
    Fehler gefunden! send() über den falschen Socket 🙄



  • Ist kein Windowsprogramm, habe also auch keinen Windows-Handle!

    #include "SDL_syswm.h"
    SDL_SysWMinfo wmInfo;
    SDL_GetWMInfo(&wmInfo);
    HWND hWnd = wmInfo.window;
    


  • hellihjb schrieb:

    Ist kein Windowsprogramm, habe also auch keinen Windows-Handle!

    #include "SDL_syswm.h"
    SDL_SysWMinfo wmInfo;
    SDL_GetWMInfo(&wmInfo);
    HWND hWnd = wmInfo.window;
    

    Cool, direkt mal notiert. Danke.



  • Dein Netzwerkcode ist aber falsch! Was ist wenn recv zum Beispiel nur 1 Byte holt? Darauf muss dein Programm vorbereitet sein.



  • ausserdem sollte ein blocking recv kein grund für eine 100%ige cpu auslastung sein.



  • Das ist ja auch nur ne Testfunktion gewesen, natürlich kommen da noch Routinen rein, die die Daten auf Vollständigkeit prüfen.

    Die CPU-Last entsteht durch das OpenGL-Rendering.



  • net schrieb:

    ausserdem sollte ein blocking recv kein grund für eine 100%ige cpu auslastung sein.

    Danke. Wenigstens einer denkt bevor er schreibt. f'`8k

    Gruß, TGGC (\-/ returns)


Anmelden zum Antworten