UDP an mehrere Clients senden

  • VB.NET

Es gibt 31 Antworten in diesem Thema. Der letzte Beitrag () ist von nikeee13.

    UDP an mehrere Clients senden

    Hallo liebe Gemeinde,

    Ich habe hier mal eine kleine Verständnis Frage. Ich möchte gerne mit einem UDP Server Daten die empfangen werden nur durchleiten, und an eine Gruppe von Clients senden. Jetzt habe ich gesehen, das UDP eine Multicast Funktion hat.

    Jetzt stellt sich mir die Frage wie diese Multicast Funktion funktioniert, und wie ich diese benutze. So wie ich das verstanden habe, ist diese Multicast Funktion dafür verantwortlich, um Daten an eine Gruppe von Clients zu senden. Die Frage wäre da, wie ich diese Clients in die Gruppe bekomme, und wie ich Daten nur an bestimmte Clients dieser Gruppe sende. Und sogar Clients aus dieser Gruppe entferne.

    Mfg Slayers
    Multicasting funktioniert nur im lokalen Netzwerk.
    Da gibt's zwar Wege drumrum, die sind aber routerspezifisch und daher nicht zuverlaessig.
    Was meinst du mit "Gruppen versenden"?
    Wenn das Ganze ueber das Internet funktionieren soll, musst du die Pakete unicasten, d.h. an jeden Client einzeln senden.
    Oder komminiziert dein Programm nur im lokalen Netzwerk?
    Also mein Programm läuft über das Internet.

    Stell dir eine Gruppe aus 5 Clients vor die kontinuierlich Daten an einen Server senden, der die Daten an alle Clients wieder weiterleiten soll. Allerdings soll der Absender seine eigenen Daten nicht zurück gesendet bekommen, sondern nur die Daten der jeweils 4 anderen Clients.

    Mfg Slayers
    Klar komme ich durch die Firewall. Die Clients senden die Daten ja zum Server. Und der Server hat den Port offen. Also das.ist das geringste Problem.

    Und ich nutze UDP weil ich große Datenmengen transportieren möchte, bei denen es nichts ausmacht wenn das ein oder andere Paket verloren geht. Und TCP ebend nicht für mein Vorhaben gedacht ist.

    Slayers schrieb:

    Klar komme ich durch die Firewall. Die Clients senden die Daten ja zum Server. Und der Server hat den Port offen. Also das.ist das geringste Problem.

    Wie schön, aber ich spreche von den UDP-Paketen vom Server an die Clients . Wenn es Dir nichts ausmacht bei jedem Client die Ports zu öffnen dann nimm UDP
    Wenn man keine Ahnung hat. Dadurch das ich die Daten an den Server sende, kann ich auf das Paket was er mir sendet problemlos antworten so das es auch ankommt. Weil das zum Teil der lochtrick ist.

    Ausserdem war meine Frage doch eine ganz andere. Wenn man sich ein bisschen mit TCP und udp auseinander setzen würde dann wusste man das auch.
    Kangaroo, du liegst da nicht ganz richtig. Das NAT weist einem internen Endpoint einen externen zu und versendet dann das Paket. Diese Zuordnung speichert es in einer Tabelle. Kommt nun ein Paket an, sieht das NAT nach, ob an den Endpoint, von dem das Paket kommt, etwas gesendet wurde. Falls ja, wird das Paket an den Sender gesendet.

    Einfaches Beispiel:
    Ein Rechner mit der lokalen IP 10.0.0.1 ist hinter einem Router und hat Internetzugriff.
    Nun will dieser Rechner ein Paket an 12.34.56.78 auf Port 1234 senden.
    Das Socket, das das Paket sendet, bekommt vom Betriebssystem einen lokalen Port zugewiesen oder sucht ihn sich selbst aus.
    In unserem Fall wird das Paket ueber Port 1000 gesendet.
    Nun kommt also ein Paket mit dem Quellendpunkt 10.0.0.1:1000 und dem Zielendpunkt 12.34.56.78:1234 beim Router an.
    Der Router aendert nun die Quell-IP auf die externe IP und den Quell-Port zu etwas Undefiniertem. In unserem Fall wird die Quell-IP zu 87.65.43.21 geaendert und der Quell-Port zu 2000. Die Zieldaten werden nicht geaendert, logisch, sonst kommt das Paket ja nicht an.
    Nun wird das Paket an 12.34.56.78:1234 gesendet.
    Kommt nun eine Antwort zurueck, wird sieht der Router, dass diese an 87.65.43.21:2000 adressiert ist.
    Nun sieht der Router in seiner Tabelle nach und sieht, dass er diesen externen Endpunkt dem internen Endpunkt 10.0.0.1:1000 zugeordnet hat.
    Also aendert er die Zieldaten des Pakets wieder auf den lokalen Endpunkt und leitet es an den Rechner weiter.
    Und deshalb muessen Clients bei UDP-Kommunikation keinen Port freigeben.
    Allerdings gibt's da Wege drumrum. Wenn du ein wenig nachdenkst, wirst du merken, dass dieses System keineswegs perfekt ist.

    @Slayers:
    Du koenntest einen Server schreiben, bei dem sich Clienten registrieren koennen.
    Wenn nun einer der Clienten ein Paket sendet, geht der Server nach eventueller Ueberpruefung des Pakets durch seine Liste der registrierten Clienten und schickt es an jeden weiter, dessen Endpunkt nicht mit dem der Quelle des Pakets uebereinsimmt. So machen es die meisten Programme. Dafuer koenntest du aber gleich TCP nehmen.

    haiyyu schrieb:

    Kangaroo, du liegst da nicht ganz richtig.

    Du hast Recht, ich habs mittlerweile nachgelesen. Bisher war ich immer davon ausgegangen, daß dies nur bei Sessions (also TCP) funktioniert, aber da lag ich offensichtlich falsch. Bestes Beispiel für das Hole-Punching war wohl Skype.

    Danke für das ausführliche Beispiel.
    Erstmal danke dir für deine Beschreibung, wenn ich nicht am Handy wäre hätte ich ihm das selber erklärt.

    Meinst du ich könnte eine List (of IpendPoint) machen, und bei jedem ankommenden Paket schauen ob der IPEndPoint bereits in der Liste ist, und wenn nicht diesen zu der Liste hinzufügen ? Nachdem überprüft worden ist ob in Liste vorhanden oder nicht, gehe ich die Liste einfach mit einer For.schleife durch, und sende das Paket einfach an alle IPEndPoints zurück ausser von dem ich es empfangen habe ?
    Genau.
    EndPoints kannst du mit Equals vergleichen.

    VB.NET-Quellcode

    1. Dim IPE1 As EndPoint = New IPEndPoint(IPAddress.Parse("12.34.56.78"), 1234)
    2. Dim IPE2 As EndPoint = New IPEndPoint(IPAddress.Parse("12.34.56.78"), 1234)
    3. If IPE1.Equals(IPE2) Then
    4. ' gleich
    5. End If
    Ne so meinte ich das nicht. Ich meinte das eher so :

    VB.NET-Quellcode

    1. Imports System.Net.Sockets
    2. Imports System.Net
    3. Public Class Form1
    4. Private EndPointList As New List(Of IPEndPoint)
    5. Private UDPC As New UdpClient(5223)
    6. Private Sub DurchLeiten()
    7. Dim EndP As IPEndPoint = UDPC.Client.RemoteEndPoint
    8. If EndPointList.Contains(EndP) Then
    9. For Each IPE As IPEndPoint In EndPointList
    10. If IPE IsNot EndP Then
    11. UDPC.Send("Bytes", "Länge", IPE)
    12. End If
    13. Next
    14. Else
    15. EndPointList.Add(EndP)
    16. For Each IPE As IPEndPoint In EndPointList
    17. If IPE IsNot EndP Then
    18. UDPC.Send("Bytes", "Länge", IPE)
    19. End If
    20. Next
    21. End If
    22. End Sub
    23. End Class
    So ging's auch.
    Allerdings würde ich nicht die Referenz vergleichen, sondern eher den Wert.

    VB.NET-Quellcode

    1. Imports System.Net.Sockets
    2. Imports System.Net
    3. Public Class Form1
    4. Private EndPointList As New List(Of IPEndPoint)
    5. Private UDPC As New UdpClient(5223)
    6. Private Sub DurchLeiten()
    7. Dim EndP As IPEndPoint = UDPC.Client.RemoteEndPoint
    8. If Not EndPointList.Contains(EndP) Then ' Contains überprüft auf Gleichheit mit der Equals-Methode. IPEndPoint hat diese überladen, weshalb sie zurückgibt, ob die IP-Adresse und der Port gleich sind.
    9. EndPointList.Add(EndP)
    10. End If
    11. For Each IPE As IPEndPoint In EndPointList
    12. If Not IPE.Equals(EndP) Then ' Equals anstatt Referenzvergleich
    13. UDPC.Send("Bytes", "Länge", IPE)
    14. End If
    15. Next
    16. End Sub
    17. End Class
    Okay also ich habe mal etwas rum probiert. Allerdings funktioniert das nicht so wie ich mir das dachte, weil der router für jedes gesendete Paket einen neuen öffentlichen Port öffnet. So habe ich irgendwann tausende einträge von einer Ip in der Liste mit verschiedenen öffentlichen Ports.

    Wie sieht es dennit der Multicast Funktion aus ?
    Hey.

    Mich hat das auch interessiert, da ich an das Problem gar nicht gedacht hatte.
    Daher habe ich mal eben eine Frage auf Stackoverflow gestellt und auch gleich eine Antwort bekommen:
    stackoverflow.com/questions/95…dp-and-port-randomisation

    Der Autor der Antwort sagt, dass der Source-Endpoint eines Pakets nicht zur Identifikation von Clienten verwendet werden soll.
    Viel mehr sollte eine ID mitgesendet werden, die angibt, um welchen Client es sich handelt.
    Allerdings könnte man diese fälschen, weshalb vom Autor vorgeschlagen wurde, eine Checksumme zu verwenden.
    Ich bin mir noch nicht ganz sicher, wie genau das ablaufen soll, allerdings habe ich eine Vermutung.
    Ich werde den Beitrag editieren, sobald ich was neues weiß (habe mal nachgefragt).

    Achja: Multicast funktioniert nur im lokalen Netzwerk.

    // Edit: Okay, jetzt weiß ich mehr.
    Also, das Verhalten deines Routers ist äußerst ungewöhnlich und sollte eigentlich nur bei fehlerhafter Verwendung von Sockets auftreten.
    Bist du dir sicher, dass der Client nur ein Socket für den gesamten Austausch benutzt? Bei impliziter Neubindung wird natürlich der Port geändert.
    Und selbst wenn es nur ein Fehler in deinem Clientprogramm ist, sollte der Source-EP nicht als Identifizierung verwendet werden, da sich natürlich die IP-Adresse jederzeit ändern kann.
    Auch könnte man mit einer gefaketen IP-Adresse (ja, das ist möglich) das Paket faken. Generell sollte man also eine andere Methode zur Identifizierung der Clienten verwendet werden.
    Mein Vorschlag wäre, dass der Server beim Erhalt eines Registrierungs-Pakets eine ID + eine zufällige Nummer generiert und diese beiden Zahlen dem Clienten schickt.
    Der Client speichert sich nun diese Zahlen und geht beim Versand eines neuen Paketes wie folgt vor:
    In das erste Byte des Pakets wird die vom Server erhaltene ID geschrieben. Danach kommen die Daten. Danach wird eine Checksumme der Daten erstellt und diese mit der Checksumme der erhaltenen Nummer ge-XOR-t*.
    Die erhaltene Zahl wird an das Ende des Pakets gehängt. Danach wird das Paket gesendet.
    Wenn der Server das Paket nun erhält, liest er zuerst die ID aus. Ist diese nicht vorhanden, kann das Paket verworfen werden. Ansonsten werden die Daten und die Checksumme ausgelesen. Von den Daten wird eine Checksumme erstellt; diese wird mit der Checksumme der dem Clienten zugewiesenen zufälligen Nummer ge-XOR-t. Ist die erhaltene Zahl die gleiche wie die am Ende des Pakets, ist das Paket gültig. Ansonsten wird es verworfen.
    Ich bin mir nicht sicher, ob das der beste Weg ist, allerdings denke ich, dass das schon für ziemliche Sicherheit sorgt, dass das Paket wirklich vom richtigen Client ankommt.
    Du kannst es dir natürlich ein klein wenig einfacher machen und die Checksumme weglassen. Dann wäre die ID das Einzige, was einen Clienten identifiziert. Allerdings könnte so jeder Client einen anderen Clienten faken. Ob das schlimm ist, hängt von deinem Programm ab.

    *) Statt dem XOR-Verfahren könntest du die Checksumme des Pakets und die zufällige Nummer in eine große Zahl packen und von dieser dann nochmal die Checksumme bilden.
    Beispiel:
    Checksumme des Pakets (32-Bit-Zahl, hier in Hexadezimaldarstellung): AABBCCDD
    Checksumme der zufälligen Zahl (32-Bit-Zahl, Hex): 11223344
    Große Zahl (64-Bit-Zahl, Hex): AABBCCDD11223344
    Die Checksumme der großen Zahl wird angehängt.
    Code-technisch könnte das Ganze so aussehen:

    VB.NET-Quellcode

    1. Dim Data() As Byte = ' ganz viele Daten
    2. Dim RandomNumber As Integer = ' das, was vom Server bei der Registrierung erhalten wurde
    3. Dim DataChecksum As Integer = Checksum(Data) ' 32-Bit-Checksumme
    4. Dim NumberChecksum As Integer = Checksum(RandomNumber) ' 32-Bit-Checksumme
    5. Dim Num As Long = (DataChecksum << 32) Or NumberChecksum ' 64-Bit-Zahl
    6. Dim Checksum As Integer = Checksum(Num) ' finale Checksumme, die an das Paket gehängt wird


    Ich hoffe, das hat dir geholfen.
    Bei weiteren Fragen stehe ich gerne zur Verfügung. :)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „haiyyu“ ()

    Okay. Ich danke dir mal wieder für deine Hilfe. Ich bin in einer halben Stunde zuhause, dann werde ich dir auch mal ausführlich berichten, was für ein Problem ich habe.

    Mfg Slayers

    Edit : Bist du dir sicher das Multicasting nur im Lokalen Netz funktioniert ? Ich meine mal was anderes gelesen zu haben.
    Weil hier: stackoverflow.com/questions/30…lticast-over-the-internet

    Achja, mein Ansatz ist ein wenig überkompliziert, wenn du nicht gerade eine Banksoftware programmieren willst.
    Du kannst auch einfach eine Session-ID dranhängen und gut ist. So macht's PHP auch. So braucht man auch keine Client-ID mehr.