C++: Udp Kommunikation mit mehreren Gegenstellen



  • Holla!

    ich möchte ein Programm schreiben, was per Udp zyklisch sowohl Nachrichten an verschiedene Teilnehmer senden als auch empfangen kann.
    Empfang und Senden der Nachrichten soll dabei unabhängig voneinander sein, sprich: Wird eine Nachricht empfangen soll darauf geantwortet werden, schlägt allerdings z.B. ein Timeout zu, innerhalb dessen nix empfangen wurde, sollen alle Gegenstellen darüber benachrichtigt werden, etc. (Sind Teilnehmer nicht erreichbar, z.B. wegen Signalverlust, können diese Nachrichten natürlich nicht empfangen werden.)

    Ich hoffe mir kann jemand Hinweise auf einen Ansatz geben 🙂

    Mein bisheriges Vorgehen mit Sockets, sendto, select & recvfrom(http://www.c-plusplus.net/forum/p2307711#2307711) scheint mir nach weiterer Lektüre so nicht zielführend (mein beschriebenes Problem tritt mit jeder gültigen Ip im Netzwerk auf)

    Vielen Dank vorab,
    lg moon



  • Warum willst du das ueberhaupt unbedingt ueber UDP realisieren? Eine Anwendung, wie du sie beschreibst, klingt fuer mich eher danach, als wolltest du TCP. Da wird z.B. der Erhalt eines Paketes (=Nachricht in deinem Fall) automatisch bestaetigt. Auch die Sache mit den Timeouts laesst sich so relativ einfach realisieren.
    Natuerlich hat TCP einen gewissen Overhead. Aber in diesem Fall scheint TCP wirklich passender.



  • Hallo Jonas,
    das Ganze soll in ein größeres Projekt integriert werden und Udp wurde halt so festgelegt (geringer Overhead, viele Teilnehmer, extrem kurze Zykluszeiten, lange Kommunikationswege)
    also muss es für mich udp sein 🙂



  • Mmh, da scheint die Festlegung aber vor dem Bekanntwerden der Anforderungen gemacht zu worden sein... Naja, egal.
    Zunaechst muesstest du nochmal genauer Beschreiben, was deine Anforderungen sind. Was ist eine Nachricht? Text, Audio, sonstwas? Auf Nachrichten soll geantwortet werden, hast du gesagt. Soll das in beide Richtungen gehen, also Server bestaetigt/beantwortet Nachrichten des Clients und Client bestaetigt/beantwortet Nachrichten des Servers, oder sollen z.B. nur die Clients antworten, um zu zeigen, dass sie noch da sind? Soll die Verbindung zustandslos oder mit definierten Zustaenden sein? Sprich soll ein Client einfach auf gut Glueck einen UDP-Dataframe rausgeben und hoffen, dass der ankommt, oder soll ein Client erstmal eine Verbindung aufbauen, dann seine Daten senden und die Verbindung durch irgend eine bestimmte Nachricht wieder abbauen?
    Das waeren Sachen, die man erstmal wissen muesste. Beschreibe bitte exakt, was du moechtest.

    EDIT: Auch noch wichtig: Ist die Reihenfolge der Nachrichten wichtig? Oder koennen die auch durcheinander ankommen?



  • - die Nachrichten bestehen aus simplen strings
    - das Ganze soll verbindungslos geschehen, also Nachrichten werden irgendwohin gefeuert und dann hoffen, dass sie ankommen
    - Reihenfolge der Nachrichten ist nicht wichtig, first come - first serve
    - wichtig sind mir auch timeouts, also empfängt ein Teilnehmer lange nichts, sollen ausgewählte TN darüber informiert werden.
    - die Kommunikation soll in beide Richtungen möglich sein, vielleicht ein kurzes Szenario mit 5 Teilnehmern zum Verständnis:
    - A schickt B einen Befehl (einfacher String, noch keine Antwort)
    - B erfragt von C Daten zur Bearbeitung des Befehls (einfacher String)
    - C schickt String an B
    - B antwortet A
    - dazu muss B noch D und E über den ausgeführten Befehl benachrichtigen, wobei beide darauf nicht antworten (müssen/sollen). E ist nicht erreichbar und kann seine Nachricht nicht abrufen.

    Ich habe bewusst "Teilnehmer" geschrieben, leider ist mir trotz zahlreicher Literatur nicht ganz klar wer bei Kommunikation wie ich sie möchte (bisher bind auf beiden Seiten) denn nun Client und wer Server ist....

    Da ich auf keinen Fall den Eindruck erwecken möchte, dass hier meine Aufgabe komplett von anderen gelöst werden soll, schreib ich schonmal meine eigenen Ideen dazu (wobei ich aufgrund der Komplexität bei manchem kaum weiß, was es ist, geschweige denn alles ausprobieren konnte...):
    - 1 Socket pro "Kommunikationsverbindung" mit sendto, select und timeout (siehe Link oben)
    - Sockets in jedem Zyklus schließen und neu einrichten
    - 1 Socket für Senden, 1 Socket fürs Empfangen
    - non-blocking sockets
    - Recv/SendAsync (MSDN)
    - ASIO::BOOST library



  • Zum Thema Server und Client:
    Der Server bietet in der Regel einen Dienst an, der vom Client genutzt wird. Das heisst nicht, dass der Client nur empfaengt und der Server nur sendet, im Gegenteil. Der Client koennte z.B. zuerst mal eine Dienst-Anfrage an den Server schicken und dann von dem Antwort bekommen. Deswegen waere er immernoch der Client.

    Zu deinem Problem: Soll B jetzt als eine Art Server agieren? Also die Gegenstellen A, D und E reden nur mit B. Und C wird nur indierekt durch B angesprochen?
    Oder koennte D jetzt auch mit C plaudern, der dann von A was erfragt?
    Oder wills du das komplett wie ein Peer-To-Peer-Netzwerk aufbauen?

    Zur Implementierung gibt's, wie du schon gesagt hast, viele Wege. Ich haette jetzt spontan boost::asio genommen, einfach weils weit verfuegbar, etabliert und ausserdem in C++ geschrieben ist. Abhaengig davon, wie du meine Fragen beantwortest, kanns aber sein, dass man das noch mit anderen vorhandenen Libraries noch einfacher machen kann.



  • oh sorry ich seh schon ich sollte vielleicht etwas konkreter werden:

    Mein B wird mal sowas wie ein fahrender Roboter der mit Bedieneinheit (A) und mehreren Sensoren und angeschlossenen Geräten im Netzwerk (C,D,E) kommunizieren soll.
    Das einzige was ich momentan noch brauche ist nur die Implementierung der Udp-Kommunikation bei B.
    Die Bedieneinheit A kann selbst auch mit den Sensoren kommunizieren, das mache ich aber nicht.
    Somit wäre ja B mein Server, da er anbietet seine Roboter-Funktion auszuführen und A fordert ihn dazu auf.
    (Sind die Sensoren dann auch Server? Sie bieten an z.B. Lagedaten zu messen...?)

    EDIT:
    So wie ich grad lese kommt mein Aufbau wohl P2P am nächsten also nix mit Server/Client...



  • In dem Fall wuerde ich A als Client und B als Server bezeichnen, insofern liegst du schon richtig. Warum C, D und E hier Netzwerk-Punkte sein muessen, verstehe ich zwar nicht, aber was solls. Ggf. koennte man B noch als Proxy-Server bezeichnen, der die Kommunikation an C, D und E weiterleitet. Aber egal.
    Kann es dabei noch mehrere As geben? In dem Fall muesste man vllt. noch asynchrone Kommunikation unterbringen, aber das ist erstmal zweitrangig. Konkret wuerde ich das ungefaehr so machen:

    • A schickt Anfrage an B und wartet mit einem Timeout von x sec. auf Antwort. Kommt keine Antwort, ist B nicht vorhanden -> Fehler.
    • (B schickt Paket an A, um zu zeigen, dass es vorhanden ist und den Befehl akzeptiert hat.)*
    • B schickt Anfrage an gewuenschtes C, D oder E und wartet wieder mit Timeout auf die Antwort. Im Falle von Timeout wird ein Paket an A gesendet, dass Fehler auftrat. Im Falle von erfolgreichem Abfragen werden die Daten an A weitergeleitet.
    • B schickt Information, dass A was abgefragt hat, an die anderen Sensoren.
    • (A schickt Bestaetigung von Erhalt an B)**
    • (B erwartet Bestaetigung von A. Im Timeout-Fall ergreift B entsprechende Massnahmen)**

    * Wenn man das Timeout in A beispielsweise doppelt so gross, wie das Sensoren-Timeout von B waehlt, koennte man sich diesen Schritt auch sparen.
    ** Wenn es unwichtig ist, ob A empfangen hat, oder nicht, wuerde ich das weglassen. Wenn du das aber einbaust geht's schon wieder Richtung TCP...

    So koennte man es loesen. Gibt sicherlich effektivere Methoden, aber daran kannst du dich erstmal orientieren.

    EDIT: Bei Peer-To-Peer redet jeder mit jedem. Bei dir redet aber A mit B. B und A gehen also eine Client-Server Verbindung ein. Im Prinzip geht B als Client dann eine Verbindung mit C, D oder E ein. Deswegen koennte man B ja auch als eine Art Proxy sehen.
    Peer-To-Peer waere es eher, wenn A mal mit C, mal mit B reden wuerde, und in der Zeit D und E auch noch einen Plausch halten wuerden.



  • Mit

    Die Bedieneinheit A kann selbst auch mit den Sensoren kommunizieren, das mache ich aber nicht.

    meinte ich, dass A selbstständig ohne B einzubeziehen die Sensoren abfragen kann. So kann die Bedieneinheit z.B. die Daten visualisieren. Den Teil muss ich selbst nicht programmieren, der kommt von anderer Stelle.
    Somit ist mir auch egal, ob und wie A auf einen Timeout reagiert. Wichtig für mich ist nur, dass wenn ich lange von A nix bekomme, der Roboter stillsteht und B evtl. die Sensoren benachrichtigt (letzte Position speichern etc.)
    Dafür muss A zyklisch senden (das ist festgelegt). Die Sensoren senden selbst teils auch zyklisch, allerdings wesentlich langsamer als A.

    Bleibt jetzt nur die Frage, wie ich das eben tatsächlich implementiere.
    Am besten fand ich meine simple Socket-Verbindung, die so im moment nur nicht 100% funktioniert, da für ein sendto() der gegenüberliegende Socket anscheinend auch tatsächlich erreichbar sein muss, sonst beeinflusst das mein select().



  • In dem Fall koenntest du ja so eine Art Keep-Alive-Mechanismus einbauen.
    Wenns moeglichst einfach gehen soll, in B mit einem Gewissen Timeout auf ein Paket mit einem KEEPALIVE oder was weiss ich warten. Im Falle von Timeout -> stoppen, Sensoren informieren, fertig. Und A bekommt halt nen Timer spendiert, der alle, sagen wir mal 500 ms, so ein KEEPALIVE sendet.
    Wenn mans noch kompliziert machen will, koennte man noch B jeweils ein Paket mit ner Zufallszahl loschicken lassen und A muss dann ein KEEPALIVE mit derselben senden. Wobei das fuer den Anwendungszweck wohl Overkill ist.



  • das stoppen, zxklisch senden, sensoren fragen, Nachrichten generieren etc. hab ich alles schon, teils nach einem vorgegebenen Protokoll (das beschreibt, wie die Nachrichten aussehen müssen).
    den timeout egtl auch, den hatte ich mit select() http://msdn.microsoft.com/en-us/library/windows/desktop/ms740141%28v=vs.85%29.aspx realisiert. (ein select() für A, einen zweiten select() mit anderen timeouts für die sensoren).

    Also hab ich nur das Problem, die Nachrichten auch tatsächlich per Udp zu verschicken und zu empfangen.
    Ich werd mir auf dein Anraten mal ASIO anschauen, vll bringt mich das weiter.

    Wenn Du ansonsten in meiner bisherigen Lösung noch einen Fehler findest wäre ich auch sehr dankbar:
    http://www.c-plusplus.net/forum/314930


Log in to reply