Funktionen zum Herstellen einer Verbindung zwischen Teilnehmern in einem Peer-to-Peer-Netzwerkspiel

Dies ist eine Sammlung von Informationen, die ich zum Herstellen einer Verbindung zwischen Teilnehmern in einem Peer-to-Peer-Netzwerkspiel mithilfe des UDP-Protokolls benötigte.

Der Artikel richtet sich an Entwickler von Einsteigerspielen. Ich habe versucht, einen Artikel zu schreiben, den ich selbst gerne zu einem Zeitpunkt gelesen hätte, als ich gerade anfing, dieses Thema zu verstehen: Damit alle notwendigen Nuancen an einem Ort gesammelt werden und gleichzeitig nichts überflüssig ist, in einfacher Sprache und mit visuellen Bildern. Vielleicht wird jemand nützlich sein.

Erfahrene Spieleentwickler werden hier wohl kaum etwas Neues für sich finden. Aber ich werde für die Kommentare und Kommentare dankbar sein.



Netzwerkspiel mit Peer-to-Peer-Architektur


  • Jeder Spieler speichert den gesamten Status der Spielwelt und verarbeitet ihn synchron mit anderen Spielern. Jeder Spieler gibt die Aktionen des Benutzers an alle anderen Spieler weiter. Der Hauptspieler, der die anderen Spieler einsammelt, heißt Server und der Rest sind Clients. Der Server ist der wichtigste nur in der Phase des Sammelns von Spielern. Und während des Spiels gibt es keinen Hauptcomputer.
  • Dieser Ansatz weist die folgenden Merkmale auf:
    • Der Verkehr hängt nicht von der Komplexität der Spielwelt ab, sondern nur von der Anzahl der Spieler. In diesem Modus funktionieren normalerweise Echtzeitstrategien , bei denen Sie Tausende von Einheiten verarbeiten müssen.
    • Das Verkehrsaufkommen liegt in der Größenordnung von N², wobei N die Anzahl der Spieler ist. Daher ist dieser Ansatz nur für Spiele mit einer kleinen Anzahl von Spielern anwendbar.
    • Da die Daten ohne Zwischenserver direkt zwischen den Spielern übertragen werden, sind die Übertragungsverzögerungen minimal. Wenn jedoch mindestens einer der Spieler Kommunikationsprobleme hat, sind alle Spieler davon betroffen.
    • Es ist notwendig, Kommunikationskanäle zwischen allen Spielern herzustellen. Wenn sich die Spieler jedoch in verschiedenen lokalen Netzwerken befinden, ist dies nicht immer möglich.
  • Sie können TCP oder UDP verwenden, um Daten im Spiel zu übertragen.
    • TCP (Transmission Control Protocol) bietet eine zuverlässige Byte-Stream-Übermittlung. Dies vereinfacht die Implementierung des Spiels, es gibt jedoch keine Kontrolle über Datenübertragungsverzögerungen.
    • UDP (User Datagram Protocol) ist ein einfaches Paketübertragungsprotokoll ohne Gewähr für deren Zustellung. Aufgrund seiner Einfachheit wird UDP jedoch in Echtzeitsystemen verwendet, wenn es nicht akzeptabel ist, auf verzögerte oder verlorene Pakete zu warten. Die Verwendung von UDP kann Verzögerungen im Spiel verringern, erschwert jedoch die Implementierung des Spiels.
    Dieser Artikel beschreibt die Verwendung von UDP.

Herstellen einer Verbindung im lokalen Netzwerk


  • Um eine Verbindung zwischen Spielern herzustellen, muss der Client die IP-Adresse des Servers und den Port kennen, den das Spielprogramm abhört.


    • Beispielsweise hat der Computer von Spieler A eine IP-Adresse von 192.168.1.2 im lokalen Netzwerk. Spieler A startet das Spielprogramm auf seinem Computer im Servermodus und das Programm lauscht auf Port 50120. Spieler A kommuniziert diese Informationen irgendwie mit Spieler B.
    • Der Computer von Spieler B hat eine IP-Adresse von 192.168.1.5 im lokalen Netzwerk. Spieler B startet das Spielprogramm auf seinem Computer im Client-Modus und das Programm belegt Port 50150. Spieler B gibt die Serveradresse 192.168.1.2►0120 in das Spielprogramm ein und das Programm sendet eine Anfrage an den Server an die angegebene Adresse.
    • Der Server befindet sich im Standby-Modus. Nachdem er eine Anfrage von Spieler B erhalten hat, ermittelt er seine Adresse 192.168.1.5►0150. Somit haben der Client und der Server eine Verbindung hergestellt und können das Spiel starten.
  • Wenn mehrere Clients mit dem Server verbunden sind, muss der Server jedem die Adressen anderer Clients senden.


    In dem Beispiel in der Abbildung sendet Server A die Adresse von Client C (192.168.1.6►0160) an Client B und sendet die Adresse von Client B (192.168.1.5►0150) an Client C. Auf diese Weise können alle Spieler Verbindungen "mit jedem" herstellen.
  • Bei jedem Spielstart kann der Server einen beliebigen freien Port vom Betriebssystem anfordern. Es ist jedoch praktischer, immer denselben Port zu verwenden, damit der Client nicht jedes Mal einen neuen Port eingeben muss.

    Alle Ports sind in drei Bereiche unterteilt:
    • [0, 1023] - bekannt (systemisch).
    • [1024, 49151] - registriert (Benutzer). Der Port für den Server muss in diesem Bereich ausgewählt werden.
    • [49152, 65535] - dynamisch (privat). Hier weist das Betriebssystem temporäre Ports für Programme zu.

    Auf Wikipedia sehen Sie eine Liste der reservierten Ports . Als nächstes wird beispielsweise Port 49094 für den Spieleserver ausgewählt.
  • Ein Computer kann über mehrere Netzwerkschnittstellen verfügen, sowohl echte (Ethernet, WiFi) als auch virtuelle (VPN). Jede Netzwerkschnittstelle hat eine eigene IP-Adresse. Das Programm kann dem Serverbenutzer die Möglichkeit geben, die Netzwerkschnittstelle auszuwählen, über die er auf Clientanforderungen wartet. Es ist jedoch praktisch, eine spezielle Wildcard-IP-Adresse 0.0.0.0 zu verwenden . Wenn das Programm einen Socket mit dieser IP-Adresse öffnet, überwacht es den angegebenen Port für alle Netzwerkschnittstellen dieses Computers. Somit muss der Player nicht überlegen, welche Netzwerkschnittstelle er auswählen soll.
  • Sie können dem Client auch helfen und die IP-Adresse des Servers automatisch ermitteln. Wenn der Client eine Anfrage an eine spezielle Broadcast-IP-Adresse (Broadcast) sendet , werden diese von allen Computern im lokalen Netzwerk empfangen.

    Wenn die Netzwerkadresse beispielsweise 192.168.1.0 lautet, die Subnetzmaske 255.255.255.0 lautet, lautet die Broadcast-IP-Adresse 192.168.1.255.


    Wenn alle Spieleserver den Port 49094 abhören, wird das an die Adresse 192.168.1.255-00-009094 gesendete Paket von allen Spieleservern in diesem Netzwerk empfangen. Jeder Server sendet eine Bestätigung an den Absender. Auf diese Weise erhält der Client eine Liste aller Spieleserver in seinem Netzwerk und kann den Server auswählen, den er benötigt.
  • Wenn sich alle Spieler im selben lokalen Netzwerk befinden, ist es ganz einfach, Verbindungen "mit jedem" herzustellen. Aufgrund der Firewall können Probleme mit dem Clientzugriff auf den Serverport auftreten. Dies hängt jedoch vom Betriebssystem und den Sicherheitseinstellungen ab.

Herstellen einer Verbindung von einem lokalen Netzwerk zu einem Server im Internet


  • Computer sind in der Regel nicht direkt, sondern über einen Router mit dem Internet verbunden. In der Regel führt der Router eine Netzwerkadressübersetzung (NAT, Network Address Translation) durch .

    Beispielsweise befindet sich Client C im lokalen Netzwerk und hat über Router B Zugriff auf das Internet, während Server A über eine öffentliche IP-Adresse im Internet verfügt. Lassen Sie sie die folgenden Adressen haben:


    • Die Internetadresse von Server A lautet 203.0.113.2. Das Serverprogramm überwacht Port 49094.
    • Die Adresse von Router B im Internet lautet 203.0.113.5. Die Adresse von Router B im lokalen Netzwerk lautet 192.168.1.1.
    • Die Client-C-Adresse im lokalen Netzwerk lautet 192.168.1.5. Das Client-Programm belegt Port 50150 und sendet unter 203.0.113.2-00-009094 ein Paket an den Server.
    • Router B ist das Standard-Gateway in seinem lokalen Netzwerk. Das heißt, alle Pakete mit Adressen, die nicht aus dem aktuellen lokalen Netzwerk stammen, werden an dieses gesendet.
    • Der Router verfügt über eine Adressübersetzungstabelle: (interne Adresse: interner Port) - (externe Adresse: externer Port). Nachdem der Router ein Paket vom Client an den Server 203.0.113.2-00-009094 empfangen hat, wählt er einen freien externen Port aus, z. B. 52050, und erstellt einen Eintrag in der Adressübersetzungstabelle: 192.168.1.5►0150 - 203.0.113.5►2050.
    • Der Router ersetzt die interne Adresse des Absenders 192.168.1.5/100150 im Paket durch die externe Adresse 203.0.113.5/102050 und überträgt das geänderte Paket an den Server.
    • Der Server empfängt ein Paket mit der Absenderadresse 203.0.113.5► 2020 und sendet eine Antwort an diese Adresse, dh an den Router.
    • Nachdem der Router das Paket vom Server empfangen hat, sucht er in seiner Adressübersetzungstabelle nach der Empfängeradresse, ersetzt die externe Adresse 203.0.113.5►2050 des Empfängers in umgekehrter Reihenfolge durch die interne Adresse 192.168.1.5►0150 und sendet das Paket an diese Adresse, dh den Client.
    • Wenn der Client nachfolgende Pakete an den Server sendet, überprüft der Router anhand der Absenderadresse, ob ein solcher Datensatz bereits in der Tabelle vorhanden ist, und verwendet in diesem Fall den zuvor zugewiesenen externen Port, in diesem Fall 52050.
    • Somit haben der Client und der Server eine Verbindung über NAT hergestellt und können das Spiel starten. Der Server kennt jedoch nicht die interne Adresse des Clients in seinem lokalen Netzwerk und geht davon aus, dass der Client ein Router ist.
    • Der Eintrag in der Adressübersetzungstabelle ist für einen bestimmten Zeitraum gültig, normalerweise 1-3 Minuten. Daher müssen Client und Server regelmäßig Pakete austauschen, damit der Datensatz, der sie verbindet, nicht gelöscht wird. Wenn der Client nach dem Löschen des Datensatzes ein neues Paket an den Server sendet, kann dem neuen Datensatz auf dem Router ein anderer externer Port zugewiesen werden. Für den Server ist dies ein anderer Client mit einer anderen Adresse.
  • Der Router des Benutzers ist in der Regel nicht direkt mit dem Internet verbunden, sondern befindet sich im internen Netzwerk des Internetproviders. Das heißt, der Client befindet sich hinter zwei NATs.

    Zum Beispiel so:


    Das heißt, eine doppelte Übersetzung von Netzwerkadressen wird durchgeführt.
  • Es gibt verschiedene Arten von NAT:
    • Vollkegel NAT


      • Nachdem ein Eintrag in der Adressübersetzungstabelle (interne Adresse: interner Port) - (externe Adresse: externer Port) erstellt wurde, werden alle Pakete vom Absender (interne Adresse: interner Port) über (externe Adresse: externer Port) an eine beliebige Empfängeradresse übertragen.
      • Jeder externe Server kann Pakete senden an (interne Adresse: interner Port), Pakete senden an (externe Adresse: externer Port).
      Beispielsweise sendet Client C Pakete an Server A und D mit derselben externen Adresse 203.0.113.5► 202050. Wenn Server E ein Paket an diese Adresse 203.0.113.5► 202050 sendet, leitet der Router es an Client C weiter.
    • Adressbeschränkter Kegel NAT.


      • Nachdem ein Eintrag in der Adressübersetzungstabelle (interne Adresse: interner Port) - (externe Adresse: externer Port) erstellt wurde, werden alle Pakete vom Absender (interne Adresse: interner Port) über (externe Adresse: externer Port) an eine beliebige Empfängeradresse übertragen.
      • Ein externer Server (Serveradresse: Server-Port) kann Pakete nur dann an (interne Adresse: interner Port) und an (externe Adresse: externer Port) senden, wenn zuvor (interne Adresse: interner Port) Pakete an (Serveradresse: beliebig) gesendet wurden Hafen).
      Beispielsweise sendet Client C Pakete an Server A und D mit derselben externen Adresse 203.0.113.5► 202050. Server D kann über die Router-Adresse 203.0.113.5► 202050 von jedem seiner Ports ein Paket an Client C senden. Der Router leitet jedoch keine Pakete vom Server E weiter.
    • Portbeschränkter Kegel NAT.


      • Nachdem ein Eintrag in der Adressübersetzungstabelle (interne Adresse: interner Port) - (externe Adresse: externer Port) erstellt wurde, werden alle Pakete vom Absender (interne Adresse: interner Port) über (externe Adresse: externer Port) an eine beliebige Empfängeradresse übertragen.
      • Ein externer Server (Serveradresse: Serverport) kann Pakete an (interne Adresse: interner Port) und Pakete an (externe Adresse: externer Port) nur dann senden, wenn (interne Adresse: interner Port) zuvor Pakete an (Serveradresse: Port) gesendet haben Server).
      Beispielsweise sendet Client C Pakete an Server A und D mit derselben externen Adresse 203.0.113.5► 202050. Der Router leitet keine Pakete von Server E oder einem anderen Server-Port D weiter.
    • Symmetrisches NAT (Symmetric NAT).


      • Wenn derselbe interne Absender (interne Adresse: interner Port) Pakete an verschiedene Empfänger sendet (Serveradresse: Serverport), wird für jede Empfängeradresse ein separater externer Port zugewiesen und ein separater Eintrag in der Adressübersetzungstabelle verwendet.
      • Nur der externe Server (Serveradresse: Serverport), der das Paket vom internen Absender empfangen hat (interne Adresse: interner Port), kann das Paket zurücksenden.
      Beispielsweise sendet Client C Pakete an Server A unter Verwendung einer externen Adresse 203.0.113.5► 202050 und an Server D unter Verwendung einer anderen externen Adresse 203.0.113.5. 20201. Der Router leitet keine Pakete von Server E oder einem anderen Server-Port D weiter.
  • Wenn mehrere Clients mit dem Spielserver verbunden sind, müssen Sie für ein Peer-to-Peer-Spiel eine direkte Verbindung zwischen jedem Clientpaar herstellen, das den Server umgeht.

    Zum Beispiel zwei Clients C und E, die mit Server A verbunden sind:


    • Client C hat eine interne Adresse von 192.168.1.5/100150 und eine externe Adresse von 203.0.113.5/102050.
    • Client E hat eine interne Adresse von 192.168.2.5:50250 und eine externe Adresse von 203.0.113.6-062060.
    • Der Server muss jedem Client die externe Adresse des anderen Clients mitteilen.
    • In der Regel verwenden Router einen NAT-Konus mit eingeschränkten Ports. Der Router leitet Pakete nur von dem Absender (IP-Adresse und Port) an den Client weiter, an den der Client früher Pakete gesendet hat. Und wenn Client C ein Paket an Client E sendet, wird Router D dieses Paket nicht verpassen.
    • In diesem Fall wird die UDP-Lochmethode verwendet. Beide Clients müssen sich gegenseitig UDP-Pakete senden. Sobald Client C ein Paket an Client E sendet, ist Router B bereit, Pakete von Client E zu empfangen. Sobald Client E ein Paket an Client C sendet, ist Router D ebenfalls bereit, Pakete von Client C zu empfangen. Die ersten Pakete des Clients, der gestartet wurde Die erste Übertragung geht verloren. Sobald jedoch der zweite Client beginnt, Pakete zu senden, können beide Clients Pakete austauschen.
    • Wenn der Router jedoch symmetrisches NAT verwendet, wird jedem Empfänger ein neuer externer Port zugewiesen. In der Regel lässt sich nicht herausfinden, welchen Port der Router zugewiesen hat. Wenn mindestens einer der Router Symmetric NAT verwendet, ist es daher nicht möglich, eine Verbindung zwischen Clients herzustellen.
  • Befinden sich zwei Clients im selben lokalen Netzwerk, kennen sie nur die externen Adressen des jeweils anderen.


    Beispielsweise sendet Client C ein Paket an Client D an seiner externen Adresse 203.0.113.5Point2051. Router B muss dieses Paket so verarbeiten, als ob es von einem externen Netzwerk empfangen wurde, die Empfängeradresse 203.0.113.5► 20205 durch die interne Adresse von Client D 192.168.1.6►0060 ersetzen und das Paket an Client D zurück an das lokale Netzwerk senden. Diese Router-Funktion wird als NAT-Loopback ( NAT-Hairpinning ) bezeichnet. Wenn NAT-Loopback auf dem Router deaktiviert ist, kann keine Verbindung zwischen Clients hergestellt werden.
  • Clients können sich in verschiedenen lokalen Netzwerken befinden, haben jedoch über einen gemeinsamen Internetanbieter Zugriff auf das Internet.


    Wenn der NAT-Loopback auf dem Gerät des Internetdienstanbieters deaktiviert ist, kann keine Verbindung zwischen Clients hergestellt werden.
  • Was kann ich tun, wenn auf dem Router symmetrisches NAT verwendet wird oder der NAT-Loopback deaktiviert ist?

    Soweit ich weiß, besteht die einzige zuverlässige Möglichkeit, diese Probleme zu lösen, darin, Pakete nicht direkt zwischen Clients, sondern über einen Server zu übertragen. Es ist entweder erforderlich, diese Funktion im Rahmen der Peer-to-Peer-Architektur im Spielprogramm zu implementieren oder die Client-Server-Architektur zu implementieren.

    Sie können auch Drittanbieterprogramme verwenden, um ein VPN zu erstellen, z. B. LogMeIn Hamachi .

Herstellen einer Verbindung zwischen LANs im Internet


  • In der Regel hat keiner der Spieler eine öffentliche IP-Adresse und die Spieler befinden sich in verschiedenen lokalen Netzwerken hinter NAT.


    In diesem Schema sendet Client C beispielsweise Pakete an Server A unter seiner externen Adresse 203.0.113.2-022020, in der der Port von Router B ausgewählt wird. Daher spielt die Auswahl des internen Ports von Server A keine Rolle, und Sie können einen beliebigen Port auswählen. In diesem Fall kann Server A anstelle von Port 49094 einen beliebigen freien Port vom Betriebssystem anfordern, z. B. 50120.
  • Damit Server A und Client C eine Verbindung herstellen können, muss jeder von ihnen zunächst seine externe Adresse herausfinden.

    Hierfür können Sie das STUN- Protokoll (Session Traversal Utilities for NAT) verwenden .


    Das STUN-Protokoll ermöglicht es dem Client, der sich hinter NAT befindet, seine externe IP-Adresse und seinen Port zu bestimmen.

    STUN-Nachrichten werden in UDP-Paketen gesendet.

    Der Client kann auf jeden öffentlichen STUN-Server zugreifen. Eine Liste der öffentlichen STUN-Server finden Sie auf Wikipedia . Oder suchen Sie nach der Liste der öffentlichen STUN-Server .

    Diese Methode ist nicht anwendbar, wenn mindestens einer der Player am Router „Symmetric NAT“ verwendet.
  • Nachdem jeder der Spieler seine externe Adresse erfahren hat, muss er irgendwie allen anderen Spielern seine Adresse mitteilen.

    Damit die Spieler ihre Adressen austauschen können, kannst du deinen öffentlichen Server benutzen. Im Diagramm wird es als Adressserver bezeichnet.


    Dies erfordert nicht unbedingt einen dedizierten Server. Sie können jedes Hosting mit einem Webserver und mit der Unterstützung einer beliebigen Skriptsprache wie PHP verwenden. Unter Verwendung des HTTP-Protokolls muss jeder Spieler seine externe Adresse an den Adressenserver senden. Und dann fordern Sie die Adressen aller anderen Spieler an.
  • Beispielsweise kann jeder Spieleserver seine eindeutige Kennung (Spiel-ID) auf dem Adressenserver registrieren. Sie können eine beliebige Zeichenfolge als Spiel-ID verwenden, z. B. den Kurznamen (Alias) des Serverbenutzers. Der Serverbenutzer teilt die Spiel-ID irgendwie den Spielern mit, die er zu seinem Spiel einladen möchte. Und diese Spieler können dem Spiel beitreten, indem sie über die Spiel-ID vom Adressenserver die externen Adressen aller Teilnehmer an diesem Spiel anfordern.
  • Nachdem jeder Spieler die externen Adressen aller anderen Spieler erhalten hat, kann er mithilfe der UDP-Hole-Punch-Methode Verbindungen zwischen den einzelnen Spielern herstellen.

Source: https://habr.com/ru/post/de485576/


All Articles