LabVIEWForum.de
Referenzarchitektur TCP-Messaging gesucht - Druckversion

+- LabVIEWForum.de (https://www.labviewforum.de)
+-- Forum: LabVIEW (/Forum-LabVIEW)
+--- Forum: LabVIEW Allgemein (/Forum-LabVIEW-Allgemein)
+---- Forum: Datenkommunikation (/Forum-Datenkommunikation)
+---- Thema: Referenzarchitektur TCP-Messaging gesucht (/Thread-Referenzarchitektur-TCP-Messaging-gesucht)



Referenzarchitektur TCP-Messaging gesucht - Achim - 24.10.2019 17:41

Hallo Forum,
ich hoffe, jemand kann mir helfen Blink

Ich habe schon relativ viel rumgesurft und auch die LV-Beispiele angeschaut, aber so richtig weiter komme ich nicht.

Folgender Anwendungsfall:
- Eine LabVIEW-Anwendung und ein separater (Leit-) Rechner sollen Daten austauschen
- Der Leitrechner hat einen Testsequenzer inkl. DB-Kommunikation laufen, implementiert mit C#
- Der Leitrechner sendet an die LabVIEW-Anwendung (die auf einem Embedded-Win 10-PXI-Controller läuft) diverse Kommandos, mit denen Messaufgaben (Strom, Spannung, DIO, etc.) an einem angeschlossenen Prüfling angestoßen werden.
- Die LV-Anwendung erfasst die Daten und hält diese, und "irgendwann" fragt der Leitrechner die Ergebnisse ab.
- Der Leitrechner fragt außerdem zyklisch den aktuellen Status der PXI-Messmaschine ab (z.B. "Schutzhaube geschlossen", "Kontaktierung gesteckt", etc.)

Wir haben zwischen Leitrechner und PXI-Chassis eine Ethernet/TCP-Verbindung aufgebaut, ein passendes Kommunikationsprotokoll haben wir uns selber ausgedacht und implementiert.

Prinzipiell funktioniert die Kommunikation auch, allerdings haben wir immer wieder SEHR lange Antwortzeiten bzw. kann immer wieder die Kommunikation nicht aufgebaut werden, nach einem Retry funktioniert das dann. Ab und zu setzt die Kommunikation auch komplett aus, dann hilft es nur noch, die LV-Anwendung zu schließen und neu zu starten.

Leider habe ich bisher noch nirgends ein "Referenzbeispiel" gefunden, welches den korrekten Aufbau einer solchen Kommunikation veranschaulicht. Die LV-Beispiele, z.B. "Simple TCP", zeigen im Prinzip immer den Aufbau eine persistenten Verbindung zwischen zwei LV-VIs auf einem gemeinsamen Rechner, auf dem "ich" die Partner sozusagen beide "in der Hand" habe und irgendwie auf Fehler reagieren kann.

Nach meiner Kenntnis ist es aber "in echt", d.h. z.B. bei Internet-Verbindungen so, dass irgendwo ein Server steht, der auf ankommende Anfragen reagiert und eine Verbindung mit einem Client aufbaut. Dann werden "kurz" Daten ausgetauscht und die Verbindung wird (zur Schonung von Resourcen) wieder geschlossen.

Genau das haben wir auch versucht, das angehängte Bild zeigt einen Ausschnitt aus unserer Anwendung
- Wir haben einen (zu unsererer eigentlichen Anwendung) parallelen asynchronen Prozess
- In diesem Prozess sind wir der Server und lauschen wir auf Anfragen ("TCP Listen"), und wenn eine Connection zustande kommt, lesen wir (aktuell) 10 Bytes
- Diese werden verarbeitet und eine Antwort wird zurückgeschickt (ACK, OK, ERR, etc., ggf. mit zugehörigen Daten)
- Danach schließen wir die Connection (erst mal) nicht, weil man ja nicht weiß, wann die Gegenstelle (Leitrechner = Client)

Frage: Wer darf wann die Verbindung schließen?

- Schließt man die Verbindung nicht, sammeln sich im RAM sehr schnell geöffnete Verbindungen an, mit "netstat" kann man in der Konsole jede Menge "Leichen" finden, die im Status CLOSE_WAIT sind
- Google weiß Bescheid...CLOSE_WAIT entsteht dann, wenn die Gegenstelle selber schon die Verbindung geschlossen hat, auf dem lokalen Rechner aber das Close noch nicht gemacht wurde.
- Schließt man die Verbindung im nächsten Schleifendurchlauf, bevor man wieder "TCP Listen" ausführt, kann man diese Verbindungen mit "netstat" im Zustand "TIME_WAIT" finden.
- Google weiß auch hier etwas: Dieser Status bleib für einige Minuten erhalten (vier Minuten, wenn ich das richtig gesehen habe), dann räumt Windows auf.
- Innerhalb dieser Zeit bauen wir aber natürlich ständig weiter Verbindungen auf...und zwar viel schneller und mehr als abgebaut werden, der Leitrechner fragt zyklisch circa sekündlich den Status ab

Frage: Sind diese "Leichen" schädlich?



Irgendwo im NI-Forum steht zum "Create Listener" etwas, und auch in der LV-Hilfe:
"Until the top level VI containing this VI goes idle, this VI maintains a table of active listeners and the ports on which they listen, sorted by listener ID.
Subsequent calls to this VI reuse these listeners depending on the service name, port, and net address you specify.
However, if you wire a value of 0 to the port terminal and an empty string to the service name terminal, each call to this VI creates a new listener on an open port.
Therefore, if you wire the VI in this manner and specify any timeout other than the default, this VI creates a new listener on an open port each time the VI times out, which consumes socket resources.
To free socket resources in this situation, wire the listener ID terminal to the TCP Close Connection function to free the port the listener uses.
Or, wire the listener ID terminal to the TCP Wait on Listener function to listen for a connection on a single port."


Aus irgendwelchen Gründen hängt sich die Verbindung bzw. überhaupt der Versuch, Verbindungen zu erstellen auf, wenn die "Listener ID" nicht wieder geschlossen wird. Man bekommt dann in LV den Fehler 128, d.h. "Open connection limit exceeded."
Also hab ich es eingebaut...


Insgesamt ist die ganze Kommunikation nicht so zuverlässig, wie wir uns das wünschen. Aber wie kann man es besser machen?
Gibt es ein "real life" Referenz-Beispiel, wie das korrekt gemacht wird?

Aktuell bekommt der Leitrechner sehr oft Exceptions, wenn er mit meiner PXI-Maschine sprechen will:
- "Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat"
oder
- "Von der Übertragungsverbindung können keine Daten gelesen werden: Eine vorhandene Verbindung wurde vom Remotehost geschlossen."

Wenn man diese Fehlermeldungen googled, gibts dazu VIELE Posts, aber irgendwie keine Lösung. Solche Probleme haben scheinbar viele Programmierer. Aber wie geht's richtig?
Das Internet funktioniert doch auch irgendwie, und das recht zuverlässig ;-)

Was kann man tun?

Über jegliche Tipps würde ich mich freuen...

Danke schon mal!


RE: Referenzarchitektur TCP-Messaging gesucht - joerg.hampel - 24.10.2019 20:44

Achim, habt Ihr schon mal mit einem Sniffer (zB Wireshark) versucht herauszufinden, was genau an den Verbindungsabbrüchen schuld ist? Bei Klartextkommunikation ist das relativ einfach nachzuvollziehen...

Falls ich Dich nicht falsch verstehe, öffnet Ihr viele viele Listener? Ich glaube nicht, dass Dein Szenario das verlangt. Das PXI könnte als Server agieren und nur einen einzigen Listener auf einem Port öffnen. Der Leitrechner ist dann der Client und baut eine Verbindung zu diesem Port auf. Darüber kann er dann Befehle senden (TCP Write) und Antworten abfragen (TCP Read).

Der eine Listener am PXI entspricht einem geöffneten Port, über welchen eingehende Verbindungsanfragen entgegen genommen werden. So macht's zum Beispiel auch ein Webserver im Internet auf Port 80 oder 443. Geht eine Verbindung ein, gibt das "TCP Wait on Listener" VI eine "connection ID" zurück. Über diese liest das PXI dann die eingehenden Nachrichten (TCP Read) und beantwortet diese (TCP Write).

Ich schick Dir noch eine private Nachricht mit einem Beispiel.


RE: Referenzarchitektur TCP-Messaging gesucht - DerKölner - 25.10.2019 15:08

Hallo zusammen,

statt den üblichen "selbstgestrickten" Lösungen nutze ich mittlerweile sehr gerne - sofern die geforderte Performance das zulässt - WebServices.

- Ich muss mich nicht selbst ums TCP-Connection-Handling kümmern
- läuft extrem stabil
- Standardports möglich ("Firewall-friendly")
- Verschlüsselung möglich
- n Clients möglich, etc
- Als "Protokoll"/Datenformat könnte man das einfache Strings, oder XML oder - was ich sehr gerne nehme- JSON nutzen.
- JSON-String vom Host zum PXI hinschicken, per Q in den Verarbeitungsprozess und die Antwort wieder als JSON zum Host, sehr simpel umsetzbar!
(Wenn man es auf die Spitze treibt, gleich als JSON-RPC Service, dann ein klein bischen mehr Aufwand)
- zusätzlich einfaches Erstellen von WebGUIs möglich (z.B. für Config/Status Display des PXI....)

WebServer in LabVIEW ist mit wenigen Mausklicks erstellt, da gibt es mittlerweile auch ein paar sehr gute Tutorials auf den NI-Seiten. Ebenso gibt es auf Github ein Beispiel für einen kompletten LabVIEW JSON-RPC Server.
Ich arbeite selbst gerade für einige Projekte daran, wenn ich da mal ein sinnvolles Extrakt rausbekomme, poste ich es hier im Forum.

LG
Stefan


RE: Referenzarchitektur TCP-Messaging gesucht - sfk010477 - 28.10.2019 10:25

(24.10.2019 17:41 )Achim schrieb:  Folgender Anwendungsfall:
- Eine LabVIEW-Anwendung und ein separater (Leit-) Rechner sollen Daten austauschen
- Der Leitrechner hat einen Testsequenzer inkl. DB-Kommunikation laufen, implementiert mit C#
- Der Leitrechner sendet an die LabVIEW-Anwendung (die auf einem Embedded-Win 10-PXI-Controller läuft) diverse Kommandos, mit denen Messaufgaben (Strom, Spannung, DIO, etc.) an einem angeschlossenen Prüfling angestoßen werden.
- Die LV-Anwendung erfasst die Daten und hält diese, und "irgendwann" fragt der Leitrechner die Ergebnisse ab.
- Der Leitrechner fragt außerdem zyklisch den aktuellen Status der PXI-Messmaschine ab (z.B. "Schutzhaube geschlossen", "Kontaktierung gesteckt", etc.)

Wir haben zwischen Leitrechner und PXI-Chassis eine Ethernet/TCP-Verbindung aufgebaut, ein passendes Kommunikationsprotokoll haben wir uns selber ausgedacht und implementiert.

Prinzipiell funktioniert die Kommunikation auch, allerdings haben wir immer wieder SEHR lange Antwortzeiten bzw. kann immer wieder die Kommunikation nicht aufgebaut werden, nach einem Retry funktioniert das dann. Ab und zu setzt die Kommunikation auch komplett aus, dann hilft es nur noch, die LV-Anwendung zu schließen und neu zu starten.

Leider habe ich bisher noch nirgends ein "Referenzbeispiel" gefunden, welches den korrekten Aufbau einer solchen Kommunikation veranschaulicht. Die LV-Beispiele, z.B. "Simple TCP", zeigen im Prinzip immer den Aufbau eine persistenten Verbindung zwischen zwei LV-VIs auf einem gemeinsamen Rechner, auf dem "ich" die Partner sozusagen beide "in der Hand" habe und irgendwie auf Fehler reagieren kann.

Nach meiner Kenntnis ist es aber "in echt", d.h. z.B. bei Internet-Verbindungen so, dass irgendwo ein Server steht, der auf ankommende Anfragen reagiert und eine Verbindung mit einem Client aufbaut. Dann werden "kurz" Daten ausgetauscht und die Verbindung wird (zur Schonung von Resourcen) wieder geschlossen.

Genau das haben wir auch versucht, das angehängte Bild zeigt einen Ausschnitt aus unserer Anwendung
- Wir haben einen (zu unsererer eigentlichen Anwendung) parallelen asynchronen Prozess
- In diesem Prozess sind wir der Server und lauschen wir auf Anfragen ("TCP Listen"), und wenn eine Connection zustande kommt, lesen wir (aktuell) 10 Bytes
- Diese werden verarbeitet und eine Antwort wird zurückgeschickt (ACK, OK, ERR, etc., ggf. mit zugehörigen Daten)
- Danach schließen wir die Connection (erst mal) nicht, weil man ja nicht weiß, wann die Gegenstelle (Leitrechner = Client)

Moin Achim,

eine fertige Architektur habe ich aktuell nicht zur Hand, habe aber mit den TCP-VIs bislang keine so schlechten Erfahrungen gemacht.

Was mir aber bei Deinem Posting auffällt: Du baust prozessbezogen zu bestimmten Zeitpunkten Verbindungen auf Deinen LV-Server auf, um Messbefehle zu senden. Zusätzlich werden periodisch Status-Daten abgefragt. Ich vermute, dass hierin schon der Grund für die von Dir erlebten Hänger steckt: Euer Server ist nur darauf angelegt, *eine* Verbindung zu handhaben. Wenn gleichzeitig nun eine zweite Anfrage kommt, läuft diese in einen Timeout, weil der Server die zusätzliche Verbindung nicht annehmen kann.

Schau Dir dazu mal https://labviewcoder.com/2017/07/10/an-asynchronous-multi-client-tcp-server-in-labview/ an -- da wird für jede Anfrage ein neuer Handler gestartet. Dieser könnte dann über andere Kommunikationsmechanismen je nach Befehl bzw. Anfrage Deine Messungen konfigurieren oder Statusdaten auslesen und zurückschicken.

Zum Thema 'Verbindung Schließen': Wenn keine hohen Übertragungsraten ein Offenhalten der Verbindung sinnvoll werden lässt, würde ich ebenfalls nach jedem Kommunikationsende die Verbindung terminieren. Mit den asynchronen Handlern von oben wäre das einfach so, dass nach Beantworten der Client-Anfrage der Handler die Verbindung (und dann sich selbst) beendet und so aus dem Speicher wirft.

HTH,
Sebastian


RE: Referenzarchitektur TCP-Messaging gesucht - Achim - 06.11.2019 09:34

Hallo zusammen,
danke schon mal für eure Antworten. Ich bin nicht gleich dazu gekommen, weiterzumachen bzw. zu antworten. Aber jetzt....

@ Sebastian:
Dein Tipp mit den zwei Servern war vermutlich die Lösung, abschließend will ich das aber noch nicht beantworten.

@ Jörg:
Die "vielen vielen Listener" waren nur EIN Versuch unter diversen Varianten, quasi aus VerzweiflungBlush


@ all:

Ich habe es jetzt ein wenig anders aufgebaut. Das "Komfort-VI" "TCP Listen.vi" ist rausgeflogen. Dieses soll eigentlich dafür sorgen, schon aktive Listener (+ zugewiesenem Port) intern zu puffern (bzw. in einer Art Mini-"Datenbank" zu cachen), und damit verhindern, dass bei nicht zustande gekommerer Connection ein neuer Listener aufgemacht und der alte verworfen würde. Irgenwie hat das nicht geklappt, evtl. aufgrund der zeitlich asynchronen Anfragen.

Ich verwende jetzt zwei verschiedene Ports, je einen für STATUS-Abfragen und einen für CMD-Anweisungen an meinen Messrechner. Beide Listener werden initial mit "TCP Create Listener.vi" erzeugt und dann wird immer auf eine Anfrage gewartet, siehe folgendes Bild:
[attachment=60517]
Am Ende der Kommunikation wird die Connection einfach geschlossen. (Mit "netstat" kann man sehen, dass die geschlossenen Verbindungen vom Betriebssystem noch eine kleine Weile im "wait"-Zustand gehalten werden, und irgendwann verschwinden.)

Seither läuft die ganze Sache eigenlich problemlos, hin und wieder muss der Leitrechner ein Retry aufgrund fehlender Antwort machen...aber das ist ein Fehler, der quasi nicht aufzuspüren ist, weil er nicht zu reproduzieren und extrem selten ist. Wir konnten nicht soooo viel testen, im Dauerbetrieb muss man mal schauen. Bisher haben wir pro Tag vielleicht maximal zehn komplette Durchläufe (mit je ca. 12 Minuten Gesamt-Testzeit) gemacht, und da ist der Retry 1-2 mal aufgetaucht.

Mal abwarten...

Vielen Dank noch mal für euren Support!

LG
Achim


RE: Referenzarchitektur TCP-Messaging gesucht - joerg.hampel - 06.11.2019 10:42

(06.11.2019 09:34 )Achim schrieb:  Seither läuft die ganze Sache eigenlich problemlos, hin und wieder muss der Leitrechner ein Retry aufgrund fehlender Antwort machen...aber das ist ein Fehler, der quasi nicht aufzuspüren ist, weil er nicht zu reproduzieren und extrem selten ist. Wir konnten nicht soooo viel testen, im Dauerbetrieb muss man mal schauen. Bisher haben wir pro Tag vielleicht maximal zehn komplette Durchläufe (mit je ca. 12 Minuten Gesamt-Testzeit) gemacht, und da ist der Retry 1-2 mal aufgetaucht.

Schön, dass Du eine Lösung gefunden hast!

Die Anwendung so umzusetzen, dass sporadische Verbindungsaussetzer kein Problem machen, ist bei Netzwerkverbindungen immer eine gute Idee. Und auch allgemein - Resilienz schadet nie.