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
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
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.
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
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
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
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.
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.
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
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!
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?
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:
1
RETURN VALUE
2
On success, the number of bytes read is returned (zero indicates end of file),
3
and the file position is advanced by this number. It is not an error if this
4
number is smaller than the number of bytes requested; this may happen for exam‐
5
ple because fewer bytes are actually available right now (maybe because we were
6
close to end-of-file, or because we are reading from a pipe, or from a termi‐
7
nal), or because read() was interrupted by a signal. On error, -1 is returned,
8
and errno is set appropriately. In this case it is left unspecified whether the
9
file position (if any) changes.
Am Dateiende (bzw. nicht mehr existierender Verbindung, je nach Device)
wird 0 geliefert, und das nicht als Fehler betrachtet.