mikrocontroller.net

Forum: PC-Programmierung select() und erkennen ob device noch lebt.


Autor: Snowyrain (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe ein kleines C-Program für Linux geschreiben. In der 
Hauptschleife wird mittels Select auf eine einkommende TCP-Verbindung 
und gleichzeitig auf Daten von der seriellen Schnittstelle gewartet. Das 
läuft auch super, ABER: wenn das Serielle-Device entfernt wird 
(USB-Serial-Adapter) weckt select permanent den Thread auf. Wenn ich die 
Daten abhole ist immer 1Byte im Buffer.

Ich erkenne das akt. in dem ich Zähle wie häufig 1Byte empfangen wurde. 
Ab einer Grenze wird das Device als nicht mehr vorhanden angesehen.Ich 
kann das Device nicht schließen und neu öffnen. Das gibt ein segfault 
wenn das Device weg ist.

Aber das wirkt auf mich unsauber. Kann ich irgendwie an den von Select 
veränderten Strukturen erkennen ob das Device noch lebt?
Oder gibt es hierfür eine andere Möglichkeit.

Gruß

Snowyrain

Autor: Mark .. (mork)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Snowyrain,

bin zwar kein Linux-Experte, aber sollte select() nicht einen Fehler 
zurückgeben, wenn das Device entfernt wird?

MfG Mark

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hatte select() nicht auch ein FD-Set für Dateideskriptoren, die durch 
Fehler auffallen? Und für read() gibts doch errno-Werte.

Autor: Snowyrain (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vielen Dank für die Antworten. exceptfds und errno stehen jetzt auf 
meiner zuerlernen Liste.

Vielen Dank

Snowyrain

Autor: Snowyrain (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

select und read sollten doch eigentliche -1 zurückliefern wenn etwas 
nicht stimmt? oder?!? Wenn ich das device entferne liefert select 
ständig 1 und read ständig 0. Und strerror(errno) liefert ständig ein 
"Success".

Irgendwie scheint select nicht mit entfernten Geräten klarzukommen.

Ich würde nach dem Select-Aufruf (, also nachdem select den Thread 
weckt,) überprüfen ob die Devices noch leben. Gibts dafür Befehle, eine 
Art Ping für Devices?!?

Gruß

Snowyrain

Autor: Micky (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Snowyrain!

Von einem ping fuer devices ist mir nichts bekannt.

Vorschlag: select==1 und read==0 als Entfernen des Geraetes
interpretieren. Dann sofort schließen und aus der Selectliste 
rausnehmen,
anschließend eine Zeit lang abwarten, dann aber in bestimmten 
Zeitabständen versuchen, das device neu zu oeffnen.

Autor: Snowyrain (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

so habe ich es gemacht. Zudem habe ich den gesuchten "ping" gefunden. 
Ich frage die Attribute der seriellen Schnittstelle ab [tcgetattr()].

Vielen Dank

Gruß

Snowyrain

Autor: Micky (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Dir auch,

denn das mit dem tcgetattr() hatte ich vorher nicht so im Kopf.
Aber an welcher Stelle setzt Du es denn ein?
Ich vermute mal innerhalb des select(), bin mir da aber nicht sicher.

Gruß Micky

Autor: Snowyrain (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

termios.h stellt u.a. die Funktion tcgetattr() zur Verfügung. Ich frage 
hiermit einfach die Einstellungen des seriellen Ports ab. Wenn das 
fehlschlägt stimmt was mit der Schnittstelle nicht.

Ich belege select() mit einem Timeout. Zur Zeit alle 20Sek, ich werde 
später wohl auf >300Sek gehen. Jetzt wird der Errno-Wert und welchen 
Wert select zurück gibt überprüft. Zudem wird  tcgetattr() aufgerufen, 
als zusätzliche Kontrolle. Wenn etwas nicht stimmt wird die serielle 
Schnittstelle geschlossen und neu geöffnet.

Auf einem PC läuft das auch sehr stabil.

Gruß

Snowyrain

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin mir jetzt nicht ganz sicher, aber war das nicht so,
daß beim Schließen einer (Lese-) Verbindung select() aufwacht und
das Lesen eines Zeichens dann den Wert -1 alias EOF liefert
(als int, also von jedem tatsächlichen Zeichen unterscheidbar)?

Vielleicht hast du das Problem ja nur, weil du den von getc()
gelieferten Wert nicht als int mit EOF vergleichst, bevor du
ein char daraus machst?
Welches ist denn das eine Byte, das du beim Schließen bekommst?

Wenn es so ist, wie ich vermute, dann ist die Lösung relativ
einfach:
Wie gewohnt mit select() warten, wenn select() zurückkehrt
vom jeweiligen Device eine int mit getc() oder fgetc() lesen.
Falls diese int ==EOF ist, Datei schließen und vergessen.
Wenn nicht, dann zu char casten und als gelesenes Zeichen
verwenden.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, habe eben mal 'man 2 select' gelesen.
Es ist tatsächlich so, daß es das dokumentierte Verhalten von
select() ist:
Dateiende an einem Input-fd führt zu einem Rücksprung von select()
und ein anschließendes Lesen scheitert.
Genau das ist dann das Zeichen dafür, die Datei schließen und
vergessen zu können. Man muß sie natürlich dann auch aus dem
Satz der FDs für den nächsten select()-Aufruf entfernen und hat
dann seine Ruhe.

Autor: Snowyrain (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

dass mit dem EOF klingt gut. Ich werde es die Tage testen. Es würde 
meinen Code echt lesbarer machen. Und vor allem vernünftig.

Vielen Dank, ich melde mich wenn ich mehrt weiß

Snowyrain

Autor: zwieblum (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das mit EOF ist eine kleine falle. wenn z.b. ein usb-seriell-adapter 
angeschlossen ist und du ein programm laufen hast, das das device offen 
hält und du dann den wandler abziehst, dann kehrt select() sofort zurück 
aber read() liefert 0 byte und sussess!

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
EOF bekommt man doch nicht von read(), sondern wenn man getc()
oder fgetc() aufruft.
read() liefert im Fehlerfall 0 stattdessen, ja.

Ich baue zwar gerne Fallen, aber hier sehe ich keine.
Habe ich etwas übersehen? Sussess?

Autor: zwieblum (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sorry, typo. read sollte irgendeinen fehler liefern, tut es aber nicht.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was lieferte denn dann? 0? Genau das ist der gemeldete Fehler!

Wenn select() für einen fd Lesebereitschaft signalisiert, das
anschließende Lesen aber nichts liefert (EOF bei getc()/fgetc(),
0 bei read()), dann ist das genau der Tip, den fd in die Tonne
treten zu können und die Datei zu schließen.

(Liefert read() nicht 0 (nichts gelesen) und auch nichts >0
(Anzahl gelesener Byte), sondern -1, dann ist das ebenfalls
als Fehler zu sehen und zusätzlich kann man errno auswerten
(und danach hoffentlich wieder zu 0 setzen).

Lt. snowyrain liefert aber select() 1 und read() 0, und genau
das ist doch das der erste Fall.)

aus man 2 read:
RETURN VALUE
       On  success,  the number of bytes read is returned (zero indicates end of file),
       and the file position is advanced by this number.  It is not an  error  if  this
       number  is smaller than the number of bytes requested; this may happen for exam‐
       ple because fewer bytes are actually available right now (maybe because we  were
       close  to  end-of-file,  or because we are reading from a pipe, or from a termi‐
       nal), or because read() was interrupted by a signal.  On error, -1 is  returned,
       and errno is set appropriately.  In this case it is left unspecified whether the
       file position (if any) changes.

Am Dateiende (bzw. nicht mehr existierender Verbindung, je nach Device)
wird 0 geliefert, und das nicht als Fehler betrachtet.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.