# Verbindungsabbruch mit Libnodave schneller erkennen



## Earny (30 März 2015)

Ich benutze das Lifebit-Prinzip, um Verbindungsabbrüche von der Visu zur S7-CPU zu erkennen. Die S7-CPU setzt einen Merker zylisch auf "1". Die Visu fragt über DaveReadBits(...) den Wert dieses Merkers in einer Timer-Prozedur ab. Wenn die Abfrage den Wert "1" liefert, ist die Verbindung OK. Anschlißend wird der Merker mit daveWriteBits(...) wieder auf "0" gesetzt.
Das funktioniert.
Die Reaktionsdauer bei einem Verbindungsabbruch ist mir mit ca. 10s allerdings zu lang. Bei einem Verbindungsabbruch liefert daveReadBits erst nach ca. 10s den Rückgabewert ungleich 0 (Fehler). Dazwischen hängt die Applikation innerhalb der Timer-Prozedur fest (grundsätzlioch OK). Ich würde nur gern den Zeitwert auf z.B. 5s herabsetzen. Es könnte dann also auf Verbindungsabbrüche schneller reagiert werden.
Gibt es eine Möglichkeit, den Zeitwert z. B. mit Libnodave-Methoden herabzusetzen.


----------



## Ralle (30 März 2015)

Wenn du ohnehin schon ein Lifebit nutzt, dann kannst du doch z.Bsp. einen 0,5-Sekunden Blinktakt als Lifebit senden und dieses Bit auch zurücksenden. Die Visu überwacht dann einfach, ob das Lifebit länger als 1 Sekunde True oder False ist, dann hat man ein Verbindungsproblem. Gleiches kann man in der SPS machen, mit dem zurückgesendeten Bit, wenn nötig oder gewünscht. Der Takt hängt von der Geschwindigkeit deiner Verbindung ab, das kannst du ja leicht ausprobieren.


----------



## tnt369 (30 März 2015)

ohne jetzt auf Libnodave einzugehen:
Ich nutze ein "Bidirektionales" Lebenszeichen indem ich z.B. einen Wert (INT) jede Sekunde (oder auch schneller) um 1 erhöhe.
Aus der Änderung erkennt dann der Verbindungspartner ob der Gegenüber noch aktiv ist. Zudem bekomme ich daraus noch
Informationen über die Verbindungsgeschwindigkeit (Differenz des aktuellen Wert zum letzten Wert.
Als Reaktionszeit auf ausbleibende Werte habe ich meist ca. 2-3 Sekunden eingestellt.


----------



## PN/DP (30 März 2015)

Du kannst mit daveSetTimeout(di, wert) eine Timeout-Zeit einstellen. Ich meine aber, daß bei den meisten Problemen diese Zeitvorgabe nicht wirkt.

Harald


----------



## Thomas_v2.1 (30 März 2015)

Unter Windows hat daveSetTimeout meines Wissens nach für eine TCP-Verbindung keine Funktion, da unter Windows select() nicht verwendet wird. Ein geändertes Timeoutverhalten für TCP/IP lässt sich auch nicht so ohne weiteres nachrüsten. Zumindest wären dann einige Änderungen in der nodave.c notwendig. Als Anhaltspunkt kann man sich da mal bei snap7 was abgucken, dort funktioniert das nämlich auch unter Windows.


----------



## Jochen Kühner (30 März 2015)

Also Ich den timeout in meiner Bibliothek so realisiert, das ich die Verb. In einem Thread starte, welchen Ich nach einem timeout kille!


----------



## Earny (30 März 2015)

Ich teste bei einer Ethernet-Verbindung zu einer 314C-2PN/DP und benutze das ISO-Over-TCP und frage in einer Timer-Prozedur ca. alle 100 MS den Lebensbit-Merker ab (wie oben beschrieben).

Nach meiner Beobachtung hängt sich die 
res = daveReadBits(...) ca. 10s lang auf, wenn keine Verbindung mehr zur CPU besteht. Es ist dann unerheblich, ob von der CPU keine 0-1-Folgen mehr kommen, oder ob versucht wird einen Integer rauf- oder runter zu zählen. Oder habe ich da irgendwas nicht verstanden?

Ich schätze: Wenn keine Verbindung mehr besteht, hängen sich alle Lese- und Schreibmethoden von Libnodave für ca. 10s auf. In dieser Zeit reagiert dann auch meine Anwendung nicht mehr. Getestet habe ich das aber nur mit daveReadBits(...).

Das setTimeOut habe ich eben getestet. Die Zeiteinstellung ist wirkungslos.

Wie man einen Thread killen kann, der sich für 10s aufgehängt hat, entzieht sich meiner Kenntnis. Ich will natürlich nicht den Task-Manager von Windows einsetzen.


----------



## Thomas_v2.1 (30 März 2015)

Bei libnodave werden unter Windows blockierende Sockets verwendet. D.h. das Programm bleibt an dieser Stelle stehen, bis die Funktion (z.B. read()) entweder mit Erfolg oder mit Fehler beendet wurde. Bei TCP versucht das Betriebssystem eine bestimmte Anzahl an neuen Zustellversuchen des Telegramms, wenn vom Partner kein Ack zurückkam. Die Zeit zwischen diesen Retransmissions wird bei jedem Versuch länger. Nach einer maximalen Anzahl an Zustellversuchen gilt die Verbindung dann als gestört und die Funktion kehrt mit Fehler zurück.

Wenn du an libnodave nichts ändern willst, wäre wohl die Lösung von Jochen eine Möglichkeit, wenn auch mit der Holzhammermethode.
Mit Änderung an libnodave müsste man die Lese-Funktion ändern, und dem read()-Aufruf einen Aufruf von select() mit der entsprechenden Timeoutzeit voranschicken.
Siehe hier:
http://vichargrave.com/tcpip-sockets-with-time-out-capabilities/

Eine Fehlererkennung auf 1 Sekunde heruntersetzen zu wollen, widerspricht allerdings dem Prinzip von TCP.


----------



## Earny (30 März 2015)

Besten Dank für Eure Mühe. 
Ich nehme dann mal zur Kenntnis, dass ich mit dem TimeOut auch weiterhin leben muss.


----------



## Thomas_v2.1 (30 März 2015)

Ich habe gerade bei libnodave nochmal reingeschaut. Prinzipiell scheint das mit dem timeout so wie in dem Link beschrieben vorgesehen zu sein, aber irgendwie hat das keine Funktion. Bei Snap7 ist es in gleicher Art umgesetzt, und dort funktioniert es. Ich gucke mal nach ob ich da was herausfinden kann.

Wichtig ist auf jeden Fall, daveSetTimeout nach daveNewConnection aufzurufen. Bei daveNewConnection werden die Parameter nämlich wieder überschrieben. In der testISO_TCP.c ist es anders herum, d.h. ohne Funktion.


----------



## Thomas_v2.1 (30 März 2015)

Was ich sehe ist das mit dem timeout bei TCP-Funktionen bei libnodave in der 0.8.5 hinzugekommen. Da sollte es eigentlich funktionieren, bzw. funktioniert bei mir. Wenn du am Timeout nichts umstellst, ist 1,5 Sekunden der Vorgabewert.


----------



## Earny (31 März 2015)

Ich habe meine alte libnodave.dll durch die neue 0.8.5 ersetzt.
Jetzt funktioniert die Einstellung des timeout:

Durch Ausprobieren habe ich herausgefunden:
daveSetTimeout(di, 1000000) erzeugt ein Timeout von ca. 2s
daveSetTimeout(di, 2000000) erzeugt ein Timeout von ca. 4s
daveSetTimeout(di, 4000000) erzeugt ein Timeout von ca. 8s
daveSetTimeout(di, 8000000) erzeugt ein Timeout von ca. 16s

Die neue libnodave.dll ist schlanker geworden. Sie hat jetzt nur noch 128kB, meine alte hatte 145kB.

Muss ich beim Ersatz der alten durch die neue libnodave.dll irgendwas beachten. Ich setze die libnodave.dll zusammen mit dem Libnodave-Modul für VB.NET ein, d.h. ohne libnodave.net.dll.


----------



## JohnCarnage (28 April 2015)

Das sollte man doch generell anders lösen?

Read Async zum MainThread und Timeout im MainThread auswerten? Zusätzlich ein Async Ping auswerten...

So verwende ich außerdem multiple Connections um die Performance zu verbessern. Manche Cpus können bis zu 16 Verbindungen


----------

