UDP Zu langsam?
Übersicht

![]() |
CykidBetreff: UDP Zu langsam? |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hallo!
Ich habe folgendes Problem: Ich beschäftige mich im Moment mit UDP und habe da leider noch nicht viel gemacht. Mein Problem ist das der Client dem Server schickt "Hey, ich will mich nach rechts bewegen". Der Server verändert die X Position +1 und sendet sie dann im nächsten durchlauf an alle Clients. Das ganze dauert aber 3,4 Sekunden bis sich mein Rechteck bewegt. Das ganze hat leider ein Haufen Includes aber ich denke das ich das wichtigste hier zusammenpacke: Der Serverteil der auf Nachrichten wartet: BlitzBasic: [AUSKLAPPEN] Function rec_Message() Der Senden Teil des Clients BlitzBasic: [AUSKLAPPEN] Function sendMovements() Der Senden Teil des Servers BlitzBasic: [AUSKLAPPEN] Function send_ClientsInfo() Der Empfangen Teil des Clients BlitzBasic: [AUSKLAPPEN] Function rec_Message() Seht ihr vlt. woran es liegen kann das es Local mit nur einem Client so lange dauert? Ich wäre euch sehr verbunden. Viele Grüße, ein hoffnungsloser Anfänger ![]() |
||
![]() |
DAK |
![]() Antworten mit Zitat ![]() |
---|---|---|
Wenn es lokal mit nur einem Client so lahm ist, dann liegt es ziemlich sicher nicht an UDP. Hast du schon versucht, die Funktionen zu profilen? Lass jede Funktion 100 oder 1000 mal in einer For-Schleife laufen, und miss die Zeit, die es dafür braucht (mittels MilliSecs()). Dann weist du, welche Funktion du beschleunigen musst.
Keine deiner Funktionen sollte länger als 1 ms pro Durchlauf brauchen. Auch kannst du in die Funktionen selbst einen Aufrufzähler einbauen und so sehen, ob eine deiner Funktionen zu oft aufgerufen wird (vielleicht hast du irgendwo eine Schleife zu viel oder so). |
||
Gewinner der 6. und der 68. BlitzCodeCompo |
![]() |
BladeRunnerModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
Grade UDP sollte wirklich schnell sein, Speedprobleme gibt es eher mit TCP/IP, da Blitz hier wartet bis die Sendebestätigung da ist. Der Fehler wird also, wie DAK es schon erwähnte, wohl eher woanders im Code zu finden sein. | ||
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3 Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64 B3D BMax MaxGUI Stolzer Gewinner des BAC#48, #52 & #92 |
![]() |
Cykid |
![]() Antworten mit Zitat ![]() |
---|---|---|
Es sollte nicht am Server liegen, der läuft in unter einer MS.
Beim Client kann ich mir nicht erklären woran es liegt. Er verbindet sich und sendet "hallo" und seinen Namen. Der Server begrüßt ihn zurück, trägt ihn ein, und sendet die Koords. Die bekommt der Client umgehend. Er beginnt nun einmal pro Schleifendurchlauf (Durch Timer auf 60 FPS begrenzt) ein "Alive!" zu senden damit der Server ihn nicht "Timeoutet" Der Server sendet nun einmal pro Schleifendurchlauf alle Infos an alle Clients. *Pseudocode* Code: [AUSKLAPPEN] senderliste = clientsliste for clientliste = each clientliste sende den header "ClientList" sende anzahl der Clients for senderliste = each senderliste sende x,y,name,ip next next Darauf löscht der Client seine alte Liste der Mitspieler und legt eine komplett neue an. Stellt er dabei fest das die Ip = Seine Ip ist (Die der Server zu beginn den Client mitteilt) löscht er dieses Objekt raus und gibt sich die Daten (x,y) Nun soll ein Rechteck an seinen X und Y Gezeichnet werden. Wenn er die Leertaste drückt sendet er den Server "BewegeX" und dern wert '1'. Der Server sucht in seiner Liste nach dem client und addiert seinen X Wert um den des Ursprungs. Ich hoffe ihr könnt mir folgen ![]() Gibt es allein hierbei schon einen Logikfehler? |
||
![]() |
DAK |
![]() Antworten mit Zitat ![]() |
---|---|---|
Heißt das, du schickst jedes Frame die Infos für alle Spieler, löscht die gesamte Spielerliste und erstellst sie neu? Lädst du auch alle Bilder usw. jedes Frame neu?
Du solltest nicht mehr als maximal 10x die Sekunde senden, eher Richtung 2-4 Mal die Sekunde. Den Rest musst du interpolieren / extrapolieren. Auch sollst du nicht alles löschen und neu erstellen sondern nur die benötigten Teile überschreiben. Noch eins: kanns sein, dass du beim Empfangen pro Frame nur ein Paket empfängst? Was du da machen musst ist um das Empfangen eine While-Schleife mit ReadAvail()>0 hängen. Damit kann er pro Frame mehrere Pakete lesen. Ansonsten hast du z.B. einen Client, der z.B. 2 FPS langsamer ist als der Server. Das heißt, pro Sekunde bleiben 2 Pakete liegen, die der Server geschickt, der Client aber nicht gelesen hat. Das heißt, pro Sekunde hinkt der Client dem Server um 2 Frames länger nach. Nach einer Minute sind das schon ganze 120 Frames oder 2 Sekunden. |
||
Gewinner der 6. und der 68. BlitzCodeCompo |
![]() |
Cykid |
![]() Antworten mit Zitat ![]() |
---|---|---|
Erstmal viel Dank für die Mühe meine Problematik zu verstehen! ![]() Also bei der Abfrage der Pakete so? BlitzBasic: [AUSKLAPPEN] Function rec_Message() Und das Senden des Servers reduzieren und die Clientverwaltung im Client optimieren, dann sollte es Funktionieren? |
||
![]() |
DAK |
![]() Antworten mit Zitat ![]() |
---|---|---|
Jup, die Abfrage schaut schon etwas besser aus. Was noch gut wäre, wäre wenn du Sachen mit den passenden Typen verschickst. Im Moment verwendest du nur Line für alles. Verwende für Ints ReadInt/WriteInt und für Floats ReadFloat/WriteFloat. Damit sparst du dir einiges an Daten.
Falls du willst schau dir meinen Serializer an, der packt dir automatisch die Felder die du brauchst in Minimalform. Funktioniert mit allen Streams, also Files, UDP und TCP. Wenn du nur beim Server das Senden reduzierst, aber beim Client nichts änderst, dann werden alle Sachen am Client ruckeln. Deswegen musst du beim Client aus den letzten empfangenen Daten extrapolieren. Das heißt, wenn du die Position eines Objekts plus seine Bewegungsrichtung bekommst, dann musst du beim Client die Objekte in diese Richtung weiter bewegen, um die Zeit bis zum nächsten Paket zu überbrücken. Edit: Habe beim Serializer noch all das eingebaut, was hier fehlt, schau dir mal das Ganze als Sample-Code an, vielleicht hilft es dir. |
||
Gewinner der 6. und der 68. BlitzCodeCompo |
![]() |
Cykid |
![]() Antworten mit Zitat ![]() |
---|---|---|
Habe nun das Senden reduziert auf alle 20 ms und beim Client die Bewegungen immer vorrausgerechnet und siehe da, Die Bewegungen sind Syncron und 'Weich'
Vielen dank dafür! Ich mache mich mal an die Optimierungen und versuche daraus einen kleinen Multipayer TopDown shooter zu basteln ![]() |
||
![]() |
DAK |
![]() Antworten mit Zitat ![]() |
---|---|---|
Alle 20 ms sind in den meisten Fällen (außer in einem kabelgebundenen LAN) auch zu häufig. 20 ms heißt 50 mal pro Sekunde. Das ist nur knapp weniger als die 60 FPS die du hast. Wenn du eh Client Simulation hast, dann solltest du auch mit deutlich weniger auskommen. | ||
Gewinner der 6. und der 68. BlitzCodeCompo |
Hangman |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Z.B. alle 2 Sekunden... nur um mal die Größenordnung auszusprechen.
Nicht dass aus alle 20ms ein alle 40ms wird^^ |
||
Ich habe Berthold gebrochen. |
![]() |
DAK |
![]() Antworten mit Zitat ![]() |
---|---|---|
Alle 2 Sekunden sind für einen Top-Down-Shooter schon wieder etwas selten. Das Ziel ist es, so wenig Daten wie möglich so selten wie möglich zu senden, und dabei noch ein flüssiges Spiel zu behalten.
Was auch wichtig ist, ist dass nicht alle Daten gleich oft geschickt werden müssen. Du schickst ja im Moment alle Daten aller Spieler bei jedem Update. Dabei gibt es Daten, die sich nie ändern (z.B. der Spielername), Daten die sich selten ändern (z.B. Hitpoints oder die momentan getragene Waffe) und Daten, die sich oft ändern (z.B. die Laufrichtung). So macht es dann keinen Sinn, den Spielernamen jedes Frame neu zu schicken, da das nur unnötig viel Daten braucht. Was auch Sinn macht, ist wenn du die Daten in Events und dauerhafte Sendung trennst. Dauerhafte Sendungen wären dann z.B. die Spielerposition, Events wären das Drücken der Schuss-Taste. Die dauerhaften Sendungen werden alle X ms geschickt, egal was passiert. Die Events werden nur einmalig dafür sofort geschickt, wenn sie eintreten. Auf diese Weise bleibt z.B. ein abgegebener Schuss nicht ewig in der Warteschleife für's nächste Update. Gleichzeitig wird auch nicht unnötiger Traffic im regelmäßigen Update verschwendet, wo sonst den Großteil der Zeit über drinnen stehen würde, dass der Spieler gerade nicht schießt. |
||
Gewinner der 6. und der 68. BlitzCodeCompo |
Hangman |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Theoretisch muss man ein einziges mal die absoluten Koordinaten übertragen, wenn man die Tastendrücke oder Richtungsänderungen sofort und natürlich jedes mal überträgt. Insofern sind 2s für ein Koordinatenupdate überhaupt nicht selten. | ||
Ich habe Berthold gebrochen. |
![]() |
DAK |
![]() Antworten mit Zitat ![]() |
---|---|---|
So gesehen hast du wieder recht. Ich hab nur gemeint, wenn das alles ist, was man überträgt, dann sind 2 Sec schon sehr wenig.
Die absoluten Koordinaten sollte man schon regelmäßig übertragen (nicht nur ein Mal am Anfang), da Timing-Fehler sich über die Zeit zusammen sammeln und größere Fehler verursachen. |
||
Gewinner der 6. und der 68. BlitzCodeCompo |
![]() |
Cykid |
![]() Antworten mit Zitat ![]() |
---|---|---|
Das Problem ist nur das wenn man soviel über den Client macht das ganze sehr sehr anfällig für Manipulationen ist.
Hatte erst gedacht das ich z.b. über den Client berechnen lasse ob er getroffen wurde. Als ich das ganze mit Freunden ausprobiert habe, habe ich mein eigenes Spiel mit Assembler umgeschrieben und aus ein 'jnz' ein 'jmp' gemacht, schon wars das ![]() Gibt es andere möglichkeiten oder ist es vollkommen legitim den Server berechnen zu lassen, wer getroffen wurde? |
||
![]() |
DAK |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hier macht sich am besten ein hybrider Ansatz. Du lässt alles sowohl am Client als auch am Server berechnen. Solange sich der Client gültig vom Server unterscheidet, werden seine Werte genommen, ansonsten gelten die Werte des Clients.
Das heißt, wenn der Client im letzten Netz-Frame nach rechts gelaufen ist, und der Server deswegen annimmt, dass der Client weiter nach rechts läuft, der Client aber stattdessen nach links läuft (aber nur eine realistische Distanz), dann gilt das, was der Client sagt. Wenn der Client aber nicht nur nach links, sondern doppelt so weit nach links gelaufen ist, wie er in der gegebenen Zeit dürfte, dann gilt das, was der Server sagt. Sinnvoll ist es auch hier eine kleine Toleranz (5% oder so) einzubauen, um für schwankende Latenz zu kompensieren. Oder man schickt die Zeit der Frames mit dem Frame mit (einfach den Wert von MilliSecs()) und vergleicht darauf, wie weit der Client in der Zeit kommen darf. Die endgültige Berechnung wer getroffen wurde (sowie andere wichtige Berechnungen) sollten immer am Server passieren, da es sich sonst zu leicht schummelt. Auch sollte der Server z.B. alle Inputs von toten Spielern aktiv ignorieren, und nicht nur darauf vertrauen, dass der Client eines toten Spielers keine Daten mehr sendet. |
||
Gewinner der 6. und der 68. BlitzCodeCompo |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group