2009-06-30 6 views
1

Für eine UDP-Server-Architektur, die langlebige Verbindungen haben wird eine Architektur einen Socket haben, der den gesamten eingehenden UDP-Verkehr überwacht Erstellen Sie separate Sockets für jede Verbindung mithilfe von connect(), um die Remoteadresse festzulegen. Meine Frage ist, ob es möglich ist, dies atomar ähnlich zu tun, was accept() für TCP tut.Emulation accept() für UDP (Timing-Problem beim Einrichten demultiplexter UDP-Sockets)

Der Grund für die Erstellung eines separaten Sockets und die Verwendung von connect() ist, dass es so einfach ist, die Paketverarbeitung über mehrere Threads zu verteilen und den Socket direkt mit den benötigten Datenstrukturen zu verknüpfen zum Bearbeiten. Die Demultiplexierungslogik im Netzwerkstapel leitet die eingehenden Pakete an den spezifischsten Socket weiter.

Nun meine Frage ist im Grunde, was passiert, wenn man will() für UDP so emulieren akzeptieren:

  1. Verwendung select() mit einem fd-Satz, der den UDP-Server-Socket enthält.

  2. Dann lesen Sie ein Paket aus dem UDP-Server-Socket.

  3. dann einen neuen UDP-Socket erzeugen, die dann

  4. I select() aufrufen, mit einer fd-Set an die entfernte Adresse() Ed verbinden, die die beiden Buchsen umfaßt.

  5. Was wird zurückgegeben?

gegeben, dass ein Paket irgendwo nach dem OS kommt zwischen 1 und 3.

wird das Paket an den Server-UDP-Socket demultiplext werden, oder wird es in 3 erstellt der spezielleren Buchse demultiplexiert werden Das heißt, wann findet Demultiplexing statt? Wenn das Paket eintrifft, oder muss es "als ob" geschehen, ist es bei Punkt 4 angekommen?

Follow-up-Frage für den Fall, dass das obige nicht funktioniert: Was ist der beste Weg, dies zu tun?

+0

Sind Sie sicher, dass Sie sogar einen neuen UDP-Socket erstellen können, der mit dem anderen Ende verbunden ist und immer noch denselben serverseitigen Port hat? Normalerweise würden Sie einen UDP-Socket auf einem anderen Port auf der Serverseite erstellen, der "Server-Socket" wird nur für die erste Anfrage verwendet, die weitere Kommunikation mit einem Peer findet an 2 verschiedenen Ports statt. Oder einfach nur 1 Socket auf dem Server verwenden, und es ist nicht wichtig, es zu verbinden, müssen Sie nur die Peers-Adresse notieren. UPD ist sowieso verbindungslos. – nos

Antwort

0

Dies wird nicht funktionieren.
Sie haben zwei einfache Optionen.

  1. Erstellen einer Multi-Threaded-Programm, das eine ‚Wurzel‘ Thread hören auf der UDP-Socket und ‚Dispatching‘ empfangenen Pakete auf den richtigen Thread ist auf der Quelle basiert. Dies liegt daran, dass Sie die Verarbeitung nach Quelle trennen möchten.

    • Erweitern Sie Ihr Protokoll, so dass die die Quellen eine eingehende Verbindung auf einem festen Anschluss annehmen und dann mit der Protokoll-Kommunikation fortzusetzen. In diesem Fall würden Sie die Quellanforderung an den Standard-UDP-Port (Ihrer Wahl) geben, dann antwortet Ihr Ende von einem neuen UDP-Socket auf den UDP-Port der Quellen. Auf diese Weise haben Sie einen neuen UDP-Pfad von Ihrem Ende zurück zum bekannten UDP-Port jeder Quelle initiiert. Auf diese Weise haben Sie verschiedene UDP-Sockets an Ihrem Ende.
+0

Warum funktioniert das nicht? Unter http://lxr.linux.no/linux-bk+v2.6.5/net/ipv4/udp.c#L222 finden Sie ein Beispiel für ein Betriebssystem, das auf den spezifischsten Socket demultiplext. Mein Problem mit Ihren vorgeschlagenen Lösungen besteht darin, dass Lösung 1 möglicherweise nicht skaliert wird und Pakete, die von Lösung 2 generiert werden, Clients möglicherweise nicht hinter bestimmten NATs erreichen. –

+0

Ok, ich hatte keine Ahnung, dass du bereit bist, unter der Socket-Ebene zu programmieren. – nik

0

Ich sehe, dass diese Diskussion aus dem Jahr 2009 ist, aber da es Aufspringen hält, wenn ich suche, ich dachte, ich soll meinen Ansatz teilen. Beide, um ein Feedback zu bekommen und weil ich neugierig bin, wie der Autor der Frage das Problem gelöst hat.

Die Art, wie ich Emulation UDP-Accept wählte, war eine Kombination von Nummer eins und zwei in der Antwort von Nik. Ich habe einen Root-Thread, der auf einem bestimmten Socket lauscht. Ich habe TCP aus Gründen der Einfachheit gewählt, aber das Ändern dieses Sockets auf UDP ist nicht sehr schwierig. Wenn ein Client mit UDP eine Verbindung zu meinem Server herstellen möchte, stellt er zunächst eine Verbindung mit dem TCP-Socket her und fordert eine neue Verbindung an.

Der Stamm Thread fährt dann fort, indem er einen UDP-Socket erstellt, ihn an eine lokale Schnittstelle bindet, eine Verbindung herstellt und Datenstrukturen einrichtet. Dieser Dateideskriptor wird dann an den Thread übergeben, der für die Verbindung verantwortlich sein wird. Die IP/Port-Informationen des neuen UDP-Sockets werden an den Client zurückgegeben, der einen neuen UDP-Socket erstellt und Daten an die bereitgestellte IP/Schnittstelle sendet.

Dieser Ansatz funktioniert gut für meine Verwendung, aber die zusätzlichen Schritte zum Einrichten eines Flusses führt zu einem Overhead. In manchen Fällen ist dieser Overhead möglicherweise nicht akzeptabel.