Sekundenlange Netzwerkverzögerung über LAN
-
Hallo zusammen,
ich bin gerade dabei, mein "spiel" netzwerkfähig zu machen. Es funktioniert im Prinzip auch ganz gut.
Ich sende ~30 mal pro Sekunde Daten rüber, im Moment relativ wenig, so ca. 10-30 bytes pro sendevorgang sollten es nur sein.
Ich verwende boost asio und sende alles über UDP.
Bisher habe ich nur über LAN getestet.
Meistens funktioniert es gut, aber manchmal kommt es zu sehr starken verzögerungen (ca. 1-3 sek), die auch nicht mehr weggehen, außper, wenn ich neustarte.Ich bin mir nicht sicher, wodurch das kommt.
Es könnte ein Programmierfehler sein, oder ich sende zu viel/ zu schnell übers netzwerk, obwohl ich mir letzteres nicht vorstellen kann, da mir die menge die ich verschicke (s.o.) nicht besonders viel vorkommt.
Die verzögerung tritt übrigens nur in eine Richtung auf, in die andere bleibt es ohne verzögerung.
Windows-Task-Manager zeigt unterm Netzwerk-Tab übrigens weit weniger als 1% Netzwerkauslastung auf beiden Seiten an.
Das mit der Verzögerung kommt auch nur manchmal, oft funktioniert es ohne, woran es liegt, dass das passiert, weiß ich nicht.Habt ihr eine Idee, woran das liegen kann, oder was ich machen kann um mehr rauszufinden?
-
Ich hab mal ein paar Test gemacht.
Wenn ich öfter sende (z.B. 100 mal pro Sekunde), dann passiert nach sehr kurzer Zeit und die Dauer der Verzögerung ist auch noch höher.
Wenn ich seltener Sende (z.B. 20 mal pro Sekunde), dann funktioniert es ohne Probleme (zumindest bisher).Also scheint es bei einer zu hohen Senderate trotz geringer Datenübertragung pro Paket Probleme zu geben...
Ich habe aber von Strategiespielen gehört, die zwischen JEDEM frame synchronisieren (dann allerdings nur die Eingaben).
Und wenn die das bei 60 fps machen wollen, wie soll das gehen?
Bei mir gings mit 30 mal senden pro Sekunde nicht und das über LAN und nichtmal übers Internet...Mach ich irgendwas falsch?
-
Q schrieb:
Ich habe aber von Strategiespielen gehört, die zwischen JEDEM frame synchronisieren (dann allerdings nur die Eingaben).
Und wenn die das bei 60 fps machen wollen, wie soll das gehen?um mal deine verwirrung dahingehend zu entwirren.
1. spricht man vom logik frame, das koennen z.b. 10Hz sein bei einem strategiespiel, das hat nichts mit der framerate zu tun.
2. 100%synchron bedeutet nicht dass man jedes frame daten verschickt und auf antwort wartet, so wuerde das selbst beim input heutzutage nicht mehr funktionieren. es muss lediglich der server vorgeben in welchem logik tick eine handlung ausgefuehrt wird.
-
rapso schrieb:
um mal deine verwirrung dahingehend zu entwirren.
1. spricht man vom logik frame, das koennen z.b. 10Hz sein bei einem strategiespiel, das hat nichts mit der framerate zu tun.Das ist mir bekannt, aber wenn du nur 10 mal pro Sekunde die Logik updatest, also z.B. positionen veränderst, wie willst du dann 60 verschiedene Frames pro sekunde rendern?
Oder willst du nur mit 10 Herz richtige Logik machen und dazwischen nur nen bischen positionen weitersetzen oder interpolieren?rapso schrieb:
2. 100%synchron bedeutet nicht dass man jedes frame daten verschickt und auf antwort wartet, so wuerde das selbst beim input heutzutage nicht mehr funktionieren. es muss lediglich der server vorgeben in welchem logik tick eine handlung ausgefuehrt wird
Soweit ich weiß, ist das bei RTS doch so, dass es 100% der logikframes synchronisiert wird.
Deswegen muss man z.B. auch bei wc3 auf spieler die laggen warten und man kann nicht zwischendrin joinen.
Sind halt zwei verschiedene Ansätze, also einmal nen CLient-Server-Modell mit z.B. Interpolation und einmal nen Lockstep wie das bei RTS gerne gemacht wird.Ich hab mich nen bischen umgehört und gehört, dass 60 Pakete pro sekunde über lan kein problem sein sollten. Vielleicht hab ichj irgendwo im Code fehler, die das problem verursachen, wird aber vermutlich schwierig zu finden, falls es wirklich daran liegt.
Hat noch wer tipps oder anmerkungen?Edit: Ich werd mal ein minmales Beispiel basteln und ein paar Tests machen.
Dadurch will ich dann mal etwas Klarheit bekommen. Ich bin mir ja immer noch nicht sicher, ob es nen allgemeines Netzwerkproblem ist, oder an meinem code liegt.
-
Q schrieb:
rapso schrieb:
um mal deine verwirrung dahingehend zu entwirren.
1. spricht man vom logik frame, das koennen z.b. 10Hz sein bei einem strategiespiel, das hat nichts mit der framerate zu tun.Das ist mir bekannt, aber wenn du nur 10 mal pro Sekunde die Logik updatest, also z.B. positionen veränderst, wie willst du dann 60 verschiedene Frames pro sekunde rendern?Oder willst du nur mit 10 Herz richtige Logik machen und dazwischen nur nen bischen positionen weitersetzen oder interpolieren?
die meisten spiele haben eine andere logik und anzeige framerate wuerde ich sagen, entsprechend muss man die verschiedenen dinge synchronisieren (oder im einfachen fall interpolieren wie du schon sagst).
vielleicht ist das was interesantes fuer dich http://www.gamasutra.com/view/news/35929/Opinion_Synchronous_RTS_Engines_And_A_Tale_of_Desyncs.phprapso schrieb:
2. 100%synchron bedeutet nicht dass man jedes frame daten verschickt und auf antwort wartet, so wuerde das selbst beim input heutzutage nicht mehr funktionieren. es muss lediglich der server vorgeben in welchem logik tick eine handlung ausgefuehrt wird
Soweit ich weiß, ist das bei RTS doch so, dass es 100% der logikframes synchronisiert wird.
Deswegen muss man z.B. auch bei wc3 auf spieler die laggen warten und man kann nicht zwischendrin joinen.
Sind halt zwei verschiedene Ansätze, also einmal nen CLient-Server-Modell mit z.B. Interpolation und einmal nen Lockstep wie das bei RTS gerne gemacht wird.nochmal, 100%synchron heisst nicht, dass man pro frame packete austauscht, synchron bedeutet nur dass man sich einig ist was die input daten fuer jedes dieser frames ist. laggen bedeutet dann, dass ein spieler nicht in der erwarteten zeit bestaetigt hat, dass eine handlung ausgefuehrt wird.
wenn ein server also sagt "in 500ms selektierst du in diesem bereich ..." muessen alle ein "OK" zurueckschicken, erst wenn das ankommt, schickt der server ein "ok, ihr duerft das frame in 500ms bearbeiten".
wenn niemand etwas klickt, schickt der server nur ein "bearbeitet alles an logik bis zum frame xyz" und niemand stallt wegen lag.Ich hab mich nen bischen umgehört und gehört, dass 60 Pakete pro sekunde über lan kein problem sein sollten. Vielleicht hab ichj irgendwo im Code fehler, die das problem verursachen, wird aber vermutlich schwierig zu finden, falls es wirklich daran liegt.
Hat noch wer tipps oder anmerkungen?Edit: Ich werd mal ein minmales Beispiel basteln und ein paar Tests machen.
Dadurch will ich dann mal etwas Klarheit bekommen. Ich bin mir ja immer noch nicht sicher, ob es nen allgemeines Netzwerkproblem ist, oder an meinem code liegt.ja, es klingt ein wenig als ob du noch nie mit UDP gearbeitet haettest und entsprechend garnicht die sonderheiten wie packet loss oder die sich veraendernde reihenfolge richtig verarbeitest. ein testprojekt waere ein guter einstieg in UDP ;), zwei leute die pong spiele und den mauscursor 100mal/s verschicken, mit ausgabe von packet loss usw.
-
Danke für den Link bzgl. RTS, der war sehr interessant.
Eigentlich ist das Projekt, dass ich im Moment habe nen Testprojekt gewesen, aber inzwischen ist es leider ein wenig zu groß geworden um das ganze schnell zu durchblicken und den fehler zu finden.
Ich werd heute was einfacheres aufsetzen, vermutlich einfach nur konsole und paar nachrichten rüberschicken.Kannst du das denn bestätigen, dass über LAN 60mal/s oder mehr senden kein Problem sein sollte?
Packet-loss und out-of-order war mir schon bekannt. Ich habe dafür folgendes Konzept benutzt:
Ich habe reliable und unreliable nachrichten.
Reliable sind z.B. Chat-messages. Unreliable sind z.B. positionen von Objekten oder Input.
Bei jedem Sendevorgang werden zwei IDs mitgesendet.
Die erste wird jedes mal 1 hochgezählt und gibt eine Art Messagenummer an.
Die zweite ist die höchste ID, die von der anderen Person empfangen wurde.
Reliable messages werden immer wieder verschickt, solange, bis sie bestätigt wurden (durch empfangen der ID).
Bisher schien das ganze zu funktionieren, aber vll ist da irgendwo noch ein Fehler drin, der die Probleme verursacht.
Aber es kommt ja erst nach einer Zeit und auch nicht immer...
So undeterministische Fehler sind meistens schwer zu finden.
-
Q schrieb:
Kannst du das denn bestätigen, dass über LAN 60mal/s oder mehr senden kein Problem sein sollte?
hmm, ich habe ein server geschrieben der in 15Min manchmal 2Mio verbindungen verarbeitet, manchmal sind da 200 verbindungen simultan aktiv. ist zwar in diesem fall TCP, aber das sollte viel limitierender sein als UDP.
Packet-loss und out-of-order war mir schon bekannt. Ich habe dafür folgendes Konzept benutzt:
Ich habe reliable und unreliable nachrichten.
Reliable sind z.B. Chat-messages. Unreliable sind z.B. positionen von Objekten oder Input.
Bei jedem Sendevorgang werden zwei IDs mitgesendet.
Die erste wird jedes mal 1 hochgezählt und gibt eine Art Messagenummer an.
Die zweite ist die höchste ID, die von der anderen Person empfangen wurde.
Reliable messages werden immer wieder verschickt, solange, bis sie bestätigt wurden (durch empfangen der ID).
Bisher schien das ganze zu funktionieren, aber vll ist da irgendwo noch ein Fehler drin, der die Probleme verursacht.
Aber es kommt ja erst nach einer Zeit und auch nicht immer...
So undeterministische Fehler sind meistens schwer zu finden.und jede seite verarbeitet soviele packete wie in der queue sind, oder 1 pro frame? (sorry falls das obvious ist, aber ein gaengiger fehler wenn man es zum ersten mal schreibt).
-
Die ganze queue wird verarbeitet.
Soll ich mal ein bischen Code den ich für das mit den reliable/unreliable messages benutze posten?
Ist aber insgesamt relativ viel.Edit:
Hab hier mal einiges gepasted:
http://codepad.org/bqCyGfJu
Ich erwarte nicht, dass sich das jemand alles anguckt, aber falls doch jemand lust hat reinzuschaun und was entdeckt / verbesserungsvorschläge / anmerkungen hat, dann bitte her damit
-
Ich hab jetzt nochma nen kurzen Test gemacht mit relativ wenigen Zeilen und es läuft selbst mit 150 mal senden pro sekunde von ca. 100 bytes jeweils ohne probleme!
Also ist es definitiv ein Programmierfehler.
Ich habe jetzt auch eine Idee, woran es liegen könnte, bin mir aber noch nicht sicher, ob es das wirklich ist.Das Problem liegt vermutlich hier:
bool NetworkPlayerData::isMessageAccepted(int msgNo, MsgPtr msg) { if(msgNo > highestReceivedMsgNo_) { highestReceivedMsgNo_ = msgNo; return true; } if(!msg->isReliable()) { return true; } return false; }
Das wird pro Message überprüft und nicht pro Paket...
Ich glaub ich hatte mal die Annahme getroffen, dass die Nachrichten innerhalb eines pakets immer nach Neuheit geordnet geschickt werden, aber ich glaube, dass das im moment nicht mehr immer so ist.
Das werd ich mal überarbeiten.Ist aber nur ne Theorie, vll ists auch was anderes.