Hallo Forum,
ich hoffe, jemand kann mir helfen
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!