Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

31

21.03.2013, 08:58

Der letzte Absatz ist aber genau das, was dot schon viel früher gesagt hat.

Nö.
Na wenn Du meinst... :rolleyes: Dann habe wohl entweder ich die Beiträge 14 und 17 falsch verstanden oder Du. In dem Fall dann wohl ich. :rolleyes:

Ich würde ein Byte mit Flags vorne ranstellen in dem es ein Bit gibt, das markiert ob die Daten gerade als Little-Endian oder Big-Endian ankommen.
Mit einer XOR verknüpfung der eigenen Byte-Order bekommt man heraus ob man ein Re-Ordering machen muss oder nicht.
Überflüssig.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

32

21.03.2013, 09:01

Dann gibt es eben keinen XBox support. Es ist und bleibt eine Frage der Anforderungen. Es muss definiert sein, zwischen welchen Plattformen kommuniziert werden soll. Diese Festlegung macht man entweder explizit indem man dies niederschreibt, oder implizit durch die Art der Realisierung, wobei das nicht der reinen Lehre vom Requirement-Engineering entsprechen würde.


Ich glaube ich "brauch" diese Anforderung ganz einfach nicht in meinem Framework :thumbsup: Das fällt dann unter die gleiche Rubrik wie mein "Events besitzen nur Primitivdaten": Limitations.

Mal was anderes: Threading.

Meine Server- und Client-Klassen verwenden mehrere Threads. Derzeit folgende:
  • Server: accept (eingehende Verbindung annehmen, IP-Ban prüfen, neuen Worker erstellen und hinzufügen)
  • pro Worker: send (für diesen Worker die ausgehenden Events versenden)
  • pro Worker: recv (für diesen Worker die eingehenden Daten in Events umwandeln)

  • pro Client: send (für diesen Client die ausgehenden Events versenden)
  • pro Client: recv (für diesen Client die eingehenden Daten in Events umwandeln)

Sind das zu viele Threads? Sollte ich z.B. send und recv jeweils zusammenfassen (d.h. pro Worker einen Thread, und auf dem Client nur einen statt zwei)? Oder ist das so vielleicht sogar sinnvoller? Die Idee dahinter war, dass ich kein weiteres Management implementieren muss (d.h. nach wie vielen versandten Events wieder geguckt wird, ob welche ankommen) ... wobei: das könnte man vielleicht auch im Wechsel machen. Nur: wo baue ich dann den Delay ein, dass meine CPU-Auslastung nicht sinnlos nach oben schnellt, wenn gar nichts gemacht wird? Bisher wird gesendet, bis kein ausgehendes Event mehr vorhanden ist und dann kurz gewartet (und anschließend weitergesendet). Das Empfangen läuft genauso: empfangen bis auf dem Socket keine Aktivität mehr ist, dann kurz warten und weiter Empfangen / bzw. gucken, ob nun Aktivität ist.

Ich hoffe ihr wisst was ich meine ^^

LG Glocke :)

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

33

21.03.2013, 09:03

Ein Thread für Send und Recv pro Client ist keine gute Lösung. Bei 300 Clients bräuchtest Du allein dafür 600 Threads. Völlig unnötig, weil es auch mit 2-3 geht (1 receive, 1-2 send dürfte ausreichen). Mehr als 10 würde ich persönlich niemals empfehlen. Bei unserem MMORPG-Server mit 2000 aktiven Spielern waren eine Hand voll Threads für die Kommunikation ausreichend. Für die Bearbeitung der Daten und der Logik hatten wir aber einen Threadpool. Wie viel da drin waren, weiß ich nicht mehr, aber da wir 16 Kerne hatten, waren's vermutlich 10-14.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

simbad

unregistriert

34

21.03.2013, 09:14

Du kannst auf die sockets warten.
Unter Linux mit select, poll oder epoll. Und Windows mit WaitForMultipleEvent und sicherlich auch mit einer fortschrittlicheren Methode.
Fürs Senden kannst du eine queue nehmen. Da wartet der Sende-Thread drauf. Immer wenn jemand was zum senden in die Queue stellt wird ein event ausgelöst. Der Thread wartet auf dieses Queue event, versucht dann alles zu verschicken, was in der queue steht. Das senden würde ich eventuell non-blocking machen. Wenn die Socket aus welchen Gründen auch immer keine Daten mehr zum senden entgegen nehmen kann gibts einen Fehlerocde. WOULDBLOCK oder so ähnlich.
Wenn die Socket wieder daten senden kann, gibt es ein entsprechendes Event das anzeigt das es weitergeht.
Diese Information, das du Datensenden kannst ist beim aufbau der Verbindung abzuwarten. Nach erfolgreichem Connect muss erst abgewartet werden, bis das Write-Event kommt. Ansonsten passiert da nix.

35

21.03.2013, 09:14

Völlig unnötig, weil es auch mit 2-3 geht (1 receive, 1-2 send dürfte ausreichen). Mehr als 10 würde ich persönlich niemals empfehlen. Bei unserem MMORPG-Server mit 2000 aktiven Spielern waren eine Hand voll Threads für die Kommunikation ausreichend. Für die Bearbeitung der Daten und der Logik hatten wir aber einen Threadpool. Wie viel da drin waren, weiß ich nicht mehr, aber da wir 16 Kerne hatten, waren's vermutlich 10-14.


Also auf dem Server generell 3 Threads? Würdest du den accepter Thread da mit in den Receive-Thread reinsetzen?

Ich könnte mir das folgendermaßen vorstellen (1 recv, 1 send):

Receive

Quellcode

1
2
3
4
5
6
7
8
solange server online:
    wenn aktivität auf listener socket:
        nimm neuen client an
    für jeden worker socket:
        solange aktivität:
            lies event
            gib event an in-queue
    delay


Send

Quellcode

1
2
3
4
5
6
7
solange server online:
    nimm event von out-queue
    solange event leer:
        delay
        nimm event von out-queue
    ermittle ziel des events (worker)
    sende event an worker


Würdest du das auf dem Client dann zusammenfassen zu einem Send/Recv-Loop? Die Sache mit dem Thread-Pool auf dem Server klingt sehr sinnvoll :)

LG Glocke

/EDIT:
Du kannst auf die sockets warten.
Unter Linux mit select, poll oder epoll. Und Windows mit WaitForMultipleEvent und sicherlich auch mit einer fortschrittlicheren Methode.
Fürs Senden kannst du eine queue nehmen. Da wartet der Sende-Thread drauf. Immer wenn jemand was zum senden in die Queue stellt wird ein event ausgelöst. Der Thread wartet auf dieses Queue event, versucht dann alles zu verschicken, was in der queue steht. Das senden würde ich eventuell non-blocking machen. Wenn die Socket aus welchen Gründen auch immer keine Daten mehr zum senden entgegen nehmen kann gibts einen Fehlerocde. WOULDBLOCK oder so ähnlich.
Wenn die Socket wieder daten senden kann, gibt es ein entsprechendes Event das anzeigt das es weitergeht.
Diese Information, das du Datensenden kannst ist beim aufbau der Verbindung abzuwarten. Nach erfolgreichem Connect muss erst abgewartet werden, bis das Write-Event kommt. Ansonsten passiert da nix.


Naja ich verwende absichtlich nicht-blockierendes Lesen vom Socket (indem ich vorher auf Aktivität prüfe; SDL_net bietet da ein paar Funktionen). Was die queues angeht: schau dir mal meine Lösung auf GitHub an :P Das geht schon in die Richtung :)

Also ca. so beim Client?

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
solange client online
    // senden bis nichts mehr zu senden
    solange trve:
        nimm event von out-queue
        wenn event leer:
            break
        sende event an server
    // empfangen bis nichts mehr zu empfangen
    solange aktivität auf socket:
        empfange event
        gib event an in-queue
    delay


Wenn am Client zu viele Events erzeugt werden, verzögert sich das Lesen neuer Events. Aber ich glaube das sollte verkraftbar sein.

LG Glocke :)

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Glocke« (21.03.2013, 09:20)


BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

36

21.03.2013, 09:23

Ein select() ist hier sicherlich die bessere Lösung als non-blocking Polling.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

37

21.03.2013, 09:31

Ein select() ist hier sicherlich die bessere Lösung als non-blocking Polling.


Was meint ihr eigentlich genau mit select()? Ich setze auf SDL_net auf und da habe ich SDLNet_TCP_Recv zum lesen und SDLNet_CheckSockets sowie SDLNet_SocketReady zum Prüfen auf Aktivität.

simbad

unregistriert

38

21.03.2013, 09:38

SDLNet_CheckSockets

ist dürfte auf select o.ä aufbauen. Du wartest da einfach ewig. Wenn die Funktion zurückkehrt ist was passiert.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

39

21.03.2013, 09:41

Um was für eine Art Spiel geht es und wieviele Clients soll der Server unterstützen?

40

21.03.2013, 09:49

SDLNet_CheckSockets

ist dürfte auf select o.ä aufbauen. Du wartest da einfach ewig. Wenn die Funktion zurückkehrt ist was passiert.


Naja sie bekommt ein SocketSet und einen Timeout. Nach dem Timeout gibt sie an, ob Aktivität auf dem Socket ist oder nicht. Will ich Lesen und dabei warten bis Daten da sind, verwende ich direkt SDLNet_TCP_Recv; lagere ich die Überprüfung vor, lese ich schließlich auch mit der Funktion, nur blockiert zwingend sie nicht weil ja prinzipiell Aktivität vorliegt.

Um was für eine Art Spiel geht es und wieviele Clients soll der Server unterstützen?


Ich will das Framework für ein Multiplayer-RPG (nicht MMORPG, eher Diablo-artig vom Netzwerk-Umfang her; also Clients im niedrigen zweistelligen Bereich) verwenden. Da sollte der obige Threading-Ansatz eigentlich vollkommen ausreichen, oder?

Werbeanzeige