Laden...

UdpClient empfängt nichts, während ein zweiter UdpClient sendet

Erstellt von 7.e.Q vor 11 Jahren Letzter Beitrag vor 11 Jahren 1.734 Views
7.e.Q Themenstarter:in
925 Beiträge seit 2004
vor 11 Jahren
UdpClient empfängt nichts, während ein zweiter UdpClient sendet

Hi Leute,

kann es sein, dass sich zwei UdpClients in die Quere kommen, wenn der eine per BeginReceive/EndReceive-Schleife auf Broadcast Pakete horcht und der andere plötzlich anfängt, auf die Adresse eines Broadcastsenders in schneller Folge Pakete abzufeuern?

Der BC-Versender schickt unentwegt UDP Pakete an die Broadcast-Adresse. Er horcht aber auch auf einem anderen Port auf eingehende UDP Pakete.

Es erscheint mir, dass der BC-Empfänger-UdpClient auf einmal mit Empfangen aufhört, solange der Sender-UdpClient seine Pakete rauspumpt. Erst wenn der Sender-UdpClient mit dem Flooden aufhört, reagiert der BC-Empfänger-UdpClient wieder...

Wireshark sagt mir, dass der BC-Versender auch noch sendet, während er den Flood empfängt und auch verarbeitet. Aber im BC-Empfängerprozess kommt halt während er flutet nix an, obwohl der UdpClient definitiv in einem BeginReceive steht.

Ist das ein erwartbares Verhalten?

Danke

Viele Grüße,
Hendrik

W
872 Beiträge seit 2005
vor 11 Jahren

Mit einer Vielzahl kleiner UDP Pakete kannst Du ganz schnell den Netzwerk-Stack des Betriebssystems lahmlegen - dann kannst Du in alle moeglichen schlechten Szenarien geraten - UDP Flood ist eine klassische denial-of-service (DoS) Attacke.
Was willst Du denn ueberhaupt erreichen?

7.e.Q Themenstarter:in
925 Beiträge seit 2004
vor 11 Jahren

Ich habe eine Steuersoftware für einen autonomen Roboter geschrieben, die mit der Roboterhardware inzwischen über UDP (vorher direkt per UART, dort kam mir ein ganz ähnliches Verhalten unter) kommuniziert. Die Firmware auf der Bridge zwischen dem CAN-Bus und dem Steuerrechner verpackt CAN-Nachrichten in ein UDP Paket und verschickt dieses an die Broadcast-Adresse des Subnetzes. Meine Software empfängt diese Pakete, wertet sie aus und verschickt ihrerseits Kommandos an die Bridge.

Die Fahr- und Drehgeschwindigkeit des Roboters ist per Regelkreis geregelt. Die Regler (P/PI/PD/PID, je nach Anwendungsfall) können während einer Regelabweichung durchaus mal bis zu 1000 UDP Pakete (Kommandos für die zwei Fahrmotoren mit Geschwindigkeit und Drehrichtung) pro Sekunde rausfeuern, die alle so ca. 20 - 30 Byte Payload haben. Damit soll möglichst verzögerungsfrei (Totzeiten sind der Tod jeder Regelung) geregelt werden können.

Als Erleichterung habe ich meiner Steuersoftware gesagt, sie soll Pakete wirklich nur noch dann rausschicken, wenn sich die Payload gegenüber dem letzten gesendeten Paket verändert hat, also keine Kommandos mehrfach. Das bewirkt schonmal eine gewisse Entlastung.

Wir nutzen UDP Broadcast, damit zur selben Zeit nicht nur der Steuer-PC im Roboter selbst, sondern auch beliebig viele Entwicklersysteme mit dem Roboter kommunizieren und die Sensordaten und Kommandos mitschneiden können. Bei UART vorher war immer nur ein Gerät zur Zeit anschließbar.

Und, bevor ihr fragt, ja, die Steuersoftware ist in C# geschrieben, der Steuer-PC läuft auf Windows 7 und es funktioniert bis auf ein paar Krücken. Sogar performant und nahezu totzeitfrei. Hätte ich auch nicht gedacht. Ist alles ein bisschen mit Kanonen auf Spatzen geschossen, aber der Effekt auf interessierte Zuschauer ist enorm beeindruckend, wenn sie die Steuersoftware in Kombination mit der auf Unity3D basierenden K.I. in Aktion sehen. 😃

W
872 Beiträge seit 2005
vor 11 Jahren

Ich wuerde Dir raten, das Lesen in einen seperaten langlaufenden Thread auszulagern, der die gelesenen Daten dann in eine Concurrent Queue ablaedt.
Das hat folgende Vorteile:*Lesen erfolgt so schnell wie moeglich, um den Netzwerkstack zu schuetzen - der Netzwerkstack wird Deine knappe Ressource sein

  • Der Ueberlauf kann programmatisch erfasst werden, wenn die ConcurrentQueue mehr als x-Elemente enthaelt - leider sieht man sonst nicht den Ueberlauf auf OS-Ebene, wenn der im Netzwerkstack passiert *Jedes Lesen mit BeginReceive erstellt ein eigenes Status-Objekt (IAsyncResult)- bei einem globalen Thread hast Du nur (wenn ueberhaupt) ein wiederverwendbares Status-Objekt

1000 Pakte/Sekunde sind sportlich, aber machbar - nichtsdestotrotz wuerde ich an Deiner Stelle mittelfristig ueber einen TCP basierten Proxy nachdenken.

7.e.Q Themenstarter:in
925 Beiträge seit 2004
vor 11 Jahren

Okay. Hab ich das korrekt verstanden, ich sollte das derzeit quasi "event"-basierte Lesen in einen Thread auslagern, der zyklisch pollt und neue Daten in eine Queue<byte[]> packt?

Die Queue<byte[]> habe ich schon, nur dass derzeit noch mittels BeginReceive/EndReceive die Datenpakete dort hineingelegt werden. Ich werde mal ausprobieren, sofern ich deinen Vorschlag richtig interpretiert habe, inwiefern Polling an dem Verhalten etwas ändert.

Bei der Gegenstelle handelt es sich zwar derzeit noch um ein C# Programm, das unter Mono auf einem RaspberryPi läuft. Jedoch wird es mittelfristig durch ein anderes ARM Cortex Board auf Basis des STM32 ersetzt, das die UDP Pakete quasi "direkt" generiert, ohne den Overhead eines CLR-Prozesses auf einem richtigen Betriebssystem. Die darauf laufende Firmware übernimmt das Verpacken direkt. Performanceprobleme sollten auf der Seite also schon bald keine Rolle mehr spielen.

Ich werde die oben erwähnt Queue<byte[]> nun, der Threadsicherheit wegen, durch eine ConcurrentQueue<byte[]> ersetzen. Bisher habe ich aber auch mit der normalen Queue keine Probleme.

W
872 Beiträge seit 2005
vor 11 Jahren

Nicht pollen - in dem eigenen Thread einfach nur synchrones-blockierendes Read und dann thread-safe weiter in eine Queue/ConcurrentQueue.

7.e.Q Themenstarter:in
925 Beiträge seit 2004
vor 11 Jahren

Ah, okay, stimmt, das geht ja auch. Ja, das probiere ich mal (Donnerstag, dann bin ich wieder im Labor)

W
872 Beiträge seit 2005
vor 11 Jahren

Du solltest ruhig weiterhin mit Events/Delegates fuer die Verarbeitung der Nachrichten arbeiten, nur sollte die Queue statt dem Netzwerkstack der Puffer fuer die Events sein.
Leider sieht man bei UDP nie anhand von Logs, wenn die Applikation zu langsam die Nachrichten abnimmt. Deswegen immer zwingend ein eigener Thread.

7.e.Q Themenstarter:in
925 Beiträge seit 2004
vor 11 Jahren

Okay, ich danke dir. Ich werde berichten, ob und was die Änderung bewirkt hat, sobald ich sie implementiert habe.