Udp Klasse für UdpConnection erstellen, Problem mit Broadcast-messages

  • VB.NET
  • .NET (FX) 4.0

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von demmy.

    Udp Klasse für UdpConnection erstellen, Problem mit Broadcast-messages

    Hi zusammen,

    ich habe ein kleines Problem mit einer "UdpConnection" Klasse die ich erstellt habe. Ich wollte eine ganz simple Klasse erstellen, die ich auf Server- sowie auf Clientseite einsetzen kann um mittels Broadcast im lokalen Netzwerk nach den entsprechenden gegenstellen zu suchen.

    Und zwar soll das ganze so ablaufen, das jenachdem welchen spezifischen Befehl ich mittels Broadcast raussende sich entsprechend alle Clients, bzw. der Server zurückmelden.
    Wird etwas empfangen, wird ein Event ausgelöst, in welchem dann ausgewertet wird worum es sich genau handelt (dieser Teil funktioniert einwandfrei).

    Nur momentan ist es so, das ich erst mal exakt das empfange, was ich selber zuvor per Broadcast gesendet habe. Das scheint mir aber irgendwie noch logisch und richtig zu sein? Also ist mein erstes Problem anhand der IP zu filtern ob die Message von mir selber kommt und dann dementsprechend diese nicht weiter zu verarbeiten, sondern zu verwerfen. Ich habe das momentan so gelöst, das ich mir eine Funktion gebastelt habe, welche die empfangene IP mit der IP von meinem PC vergleicht. Aber irgendwie gefällt mir diese Lösung noch nicht. Gibt es da eine andere Lösung für?

    Das andere und schwerwiegendere Problem ist, das nicht immer auf jede Anfrage die ich sende eine Antwort zurück kommt. Bzw. ich habe jetzt mal auf Server- und Clientseite debuggt und herausgefunden, das ich immer eine Anfrage raussende, diese auch auf der Gegenstelle ankommt und die Gegenstelle auch antwortet. Ich empfange nur nichts auf der Seite von der ich die Anfrage gesendet habe. Ich habe aktuell keine Ahnung woran das liegen kann? Das ist aber auch nicht immer so, manchmal funktioniert es. Kann es etwas damit zu tun haben das alle Teilnehmer versuchen gleichzeitig mir die Rückmeldung zu senden? Getestet habe ich es mit einem Server und 2 Clients im Netzwerk. Besonders auffällig ist dieses Phänomen, wenn längere Zeit keine Anfrage über die Udp-Verbindung gesendet wurde. Kurz nach dem Start der Testapplikationen funktioniert es meistens?

    Hier noch die Klasse der Udp-Verbindung:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Net.Sockets
    2. Imports System.Text
    3. Imports System.Net
    4. Public Class udpConnection
    5. Private UdpListener As UdpClient ' horchen
    6. Private UdpListenerPort As Integer = 9654
    7. Private UdpSender As UdpClient ' senden
    8. Private ep As IPEndPoint
    9. Private CallBack As AsyncCallback ' asyncrones Empfangen
    10. Delegate Sub DelegateWriteRtf(ByVal t As String)
    11. Private Const broadcastAddress As String = "255.255.255.255"
    12. Public Event MessageReceived(ByVal sender As udpConnection, ByVal msg As String, ByVal msg_source As String)
    13. #Region "Constructor"
    14. Sub New()
    15. StartListener()
    16. End Sub
    17. #End Region
    18. ' Startet den UDP Client zum horchen
    19. Private Sub StartListener()
    20. CallBack = New AsyncCallback(AddressOf Receive)
    21. ep = New IPEndPoint(IPAddress.Any, UdpListenerPort)
    22. UdpListener = New UdpClient(ep)
    23. UdpListener.EnableBroadcast = True
    24. UdpListener.BeginReceive(CallBack, "") ' startet asyncrones Empfangen
    25. End Sub
    26. ' Diese Sub wird in einem eigenen Thread ausgeführt
    27. Sub Receive(ByVal ar As IAsyncResult)
    28. Dim res() As Byte = UdpListener.EndReceive(ar, ep)
    29. Dim resString = Encoding.ASCII.GetString(res)
    30. If Not ep.Address.ToString = Netzwerkverbindung.IPs_v4.Item(0).ToString Then
    31. RaiseEvent MessageReceived(Me, resString, ep.Address.ToString)
    32. End If
    33. 'SyncLock UdpListener
    34. If ar.IsCompleted Then ' wenn fertig, wieder lauschen
    35. UdpListener.BeginReceive(CallBack, "")
    36. 'UdpListener.BeginReceive(New AsyncCallback(AddressOf Receive), ar.AsyncState)
    37. End If
    38. 'End SyncLock
    39. End Sub
    40. Public Sub Send(ByVal Command As String, ByVal TargetIP As String)
    41. If UdpSender Is Nothing Then
    42. UdpSender = New UdpClient()
    43. End If
    44. If Not Command = String.Empty Then
    45. Dim b() As Byte = Encoding.ASCII.GetBytes(Command)
    46. UdpSender.Send(b, b.Length, TargetIP, UdpListenerPort)
    47. End If
    48. End Sub
    49. Public Sub Send_Broadcast(ByVal Command As String)
    50. If UdpSender Is Nothing Then
    51. UdpSender = New UdpClient()
    52. End If
    53. If Not Command = String.Empty Then
    54. Dim b() As Byte = Encoding.ASCII.GetBytes(Command)
    55. UdpSender.Send(b, b.Length, broadcastAddress, UdpListenerPort)
    56. End If
    57. End Sub
    58. End Class


    Ich hoffe Ihr könnt mir weiterhelfen?

    Vielen Dank schonmal!!!
    1) Das manchmal eine Naricht nicht ankommt kann gut an Udp liegen. Wenn du jedoch Tcp nutzt, dann hast du gleich das Problem mit der "Antwort ob der Empfänger die Naricht erhalten hat" gelöst, da Tcp ein Drei-Wege-Handshake nutzt, welcher dafür sorgt, dass die Gegenseite erfährt, ob die Naricht angekommen ist. Außerdem sorgt Tcp auch dafür, dass die Naricht ankommt! Udp ist das so gesehen "egal".

    2)
    Und zwar soll das ganze so ablaufen, das jenachdem welchen spezifischen Befehl ich mittels Broadcast raussende sich entsprechend alle Clients, bzw. der Server zurückmelden.

    Hau doch die ganzen Clients in eine List(Of ) rein. Dann kannst du als Server mit ForEach alle Clienten durchgehen und anschreiben. Bei den Clients muss nur noch ein Event gefeuert werden, wenn der Inhalt einen Befehl beinhaltet der sagt, dass die Clients eine Naricht zum Server schicken sollen (Das setzt natürlich ein kleines Befehlsprotokoll vorraus).

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

    Hi,
    ja du hast recht. :) Die eigentliche Kommunikation läuft ja auch über Tcp/Ip.

    Das Udp würde ich nur gerne benutzen um einen "Broadcast-search" aller verfügbaren Teilnehmer durchzuführen.
    Um so Teilnehmer zu finden, die noch nicht in der "Teilnehmerliste" stehen. Tcp/Ip kann ja leider kein Broadcast.
    Um den Teilnehmern die bereits in der Liste stehen eine Broadcastmeldung zu schicken, lasse ich sie wie du schon gesagt hast in einer Schleife durchlaufen.

    Aber zurück zu meinem Problem, was kann ich tun das die Daten immer sauber ankommen bzw. sich alle Teilnehmer richtig melden??
    Daten würde ich prinzipiell nur über Tcp schicken oder über NamedPipes.
    Ein Vorschlag noch: Wieso setzt du das nicht so um, dass wenn ein Client gestartet wird, der Client einfach eine Naricht an den Server sendet mit "Hallo ich bin Client xy, nehme mich doch bitte in deine List auf" ^^
    Wenn der Client vorher gestartet wird, dann kann er keine Verbindung mit dem Server aufbauen. Der Client müsste sich also zu einem späterem Zeitpunkt mit dem Server verbinden, wenn dieser online ist.


    das ist schon klar, nur würde dann auch die Anfrage der Aufnahme in die Liste des Clients ins leere gehen und somit nutzlos sein oder? :)

    sind denn nun diese "Named Pipes" Broadcastfähig?

    demmy schrieb:

    Anfrage der Aufnahme
    Der Verbindungsaufbau würde schlichtweg fehlschlagen, du müsstest eben eine sessionTimedOut oder ServerUnreachableException (vermutlich nicht die richtigen Namen) abfangen. und dann wieder in 5 Minuten probieren, oder per Button. Sobald die Verbindung erfolgreich aufgebaut wurde, fügt der Server den Client entweder automatisch hinzu, oder der client meldet wohin er möchte.
    ich glaube wir sprechen gerade aneinander vorbei.

    Die ganze Client - Server-Kommunikation läuft über Tcp-Ip. Auch das anmelden des Clients am Server usw. läuft alles über Tcp/Ip. Das funktioniert alles einwandfrei. Was ich versuche umzusetzen ist auch nicht eine automatische Anmeldung des Clients am Server. Das ist schon mit drin.

    Ich möchte eigentlich nur das lokale Netzwerk "scannen" nach Servern und Clients die im Netzwerk sind und die sich verbinden könnten.

    Mit Broadcastfähig habe ich gemeint die Möglichkeit zu haben eine Message an alles im Netzwerk gleichzeitig zu schicken.
    Das kann doch Tcp/Ip nicht oder?

    Ich möchte nur erreichen, das alle Teilnehmer die mit dem spezifischen "Identifizierungsbefehl" etwas anfangen können sich bei dem sendenden zurückmelden "Hallo hier bin ich".

    Ich hoffe Ihr versteht was ich meine?

    demmy schrieb:

    Ich möchte eigentlich nur das lokale Netzwerk "scannen" nach Servern und Clients die im Netzwerk sind und die sich verbinden könnten.
    Nach Servern kannst du scannen, ja. Aber nach unverbundenen Clients kannst du nicht scannnen.
    Nach verbundenen Clients brauchst du nicht zu scannen, denn du hast dir ja hofflich die von den Clients zu deim Server hergestellten Verbindungen in einer Liste gemerkt.
    Aber das wäre ein ganz anneres Chat-Netzwerk, wenn du da mit mehreren Chat-Servern rumfuhrwerkst.
    Naja also es geht nicht um einen Chat sondern um eine Anwendung die Informationen verteilt und Visualisiert.

    Und wie stelle ich es nun am geschicktesten an, das Netzwerk nach einem Server zu scannen?

    Naja und wegen der anderen Richtung hatte ich mir überlegt, wäre es vielleicht aber auch mal ganz interessant / hilfreich zu schauen, ob es noch Clients gibt, die nicht oder nicht mehr Verbunden sind.

    Ja die bestehenden Verbindungen werden in einer Liste gespeichert.
    Es ist immer eine Sicherheitslücke, wenn von aussen ein Rechner zu iwas bewegt werden kann.
    Wenn also unverbundene Clients trotzdem antworten würden - also ich würd sowas nicht installieren.
    Ausnahme sind Server, und deshalb sind die auch besonders gefährdet.
    Naja, nach Servern scannen ist einfach: Schreibe einen Client, der sich mit jeder IP im Netzwerk zu verbinden sucht.
    Auf den Rechnern, wos klappt läuft ein Server.
    Naja also ganz so drastisch würde ich das jetzt nicht sehen, er soll sich ja nur zu erkennen geben und nicht geheime Informationen preisgeben. ;)

    Und wie soll das mit dem Scannen dann ablaufen? Es kommt doch drauf an, in welchem IP-Adressbereich ich mich bewege, jenachdem wieviele Adressen ich durchklappern muss. Wie ermittle ich denn wieviele Adressen ich da abklappern muss?

    Oder einfach nur 192.168.0.0 bis 192.168.255.255 durchgehen. Dann bin ich aber eingeschränkt in der IP-Wahl, also ich muss in diesem Adressbereich bleiben. Oder?