Socket select() unterbrechen
« | 28 Dec 2019 | »Hmm … ich könnte schwören über das Thema schon was geschrieben zu haben, doch ich finde nichts …
Kurze Frage: Wie unterbricht man ein laufendes
select()
?
Kurze Antwort: Mit close()
bzw. closesocket()
Und schon werden die Linux Benutzer
laut aufschreien …
Doch diesmal haben sie recht:
Windows ist Schuld!
Alle Socket Entwickler
kennen natürlich select()
, was benutzt wird, um auf Änderungen von
Sockets oder deren Datenpuffer effizient zu reagieren.
Man übergibt eine Liste von Sockets mit einer Bitmaske an select() und dieses wartet entweder bis zu einem gesetzt Timeout um “nichts” zu melden, oder im Moment einer Änderung (wie “hab-etwas-empfangen”) sofort zurückzukehren.
So weit, so gut.
Doch was ist, wenn man selbst ein laufendes select()
unterbrechen möchte?
Es zwingen möchte, noch vor dem zuvor gesetzten Timeout abzubrechen?
Unter Unix Systemen ist die Sache
einfach. Man erstellt eine Pipe
und hängt den Lese-Deskriptor zu den Sockets. Will man select()
von außen
unterbrechen, schreibt man einfach ein Byte in den Schreibe-Deskriptor und
select()
kehrt sofort mit der Meldung zurück, dass auf dem Lese-Teil ein
Byte angekommen ist.
Doch unter Windows funktioniert select()
ausschließlich mit Sockets und nicht
mit anderen Handles wie z.B. denen von Pipes. Der Unix-Trick funktioniert also nicht.
Jetzt könnte man unter Windows einen weiteren Socket erstellen und binden und auch dort auf ein Byte warten, das bei der gewünschten Unterbrechung versendet wird. Doch der Nachteil liegt klar auf der Hand: Die Software wird hackbar, weil per Socket eine Außenverbindung möglich wird.
Es gibt aber noch einen anderen Trick:
- Man erstelle einen ungebundenen Socket
- Der ungebundene Socket kommt ebenso in die
select()
Liste - Bei der Unterbrechung wird Socket einfach per
closesocket()
geschlossen.
Zieht man einem Windows-select()
einen Socket-Sessel unter’m Hintern weg,
so kehrt es ebenso sofort mit einer Fehlermeldung zurück.
Das ist zwar nicht so schön wie Unix-Pipe Variante, doch ich setze sie schon erfolgreich auf Windows und Windows CE seit 10 Jahren ein.
Man muss natürlich dazu sagen, dass das Verhalten nicht konkret ausformuliert ist. Und es wäre möglich, dass Windows diesen Verhaltenszug in kommenden Versionen abändert. Wahrscheinlich ist das aber nicht.
Ich gewann durch diese Methode die Möglichkeit, das “Unterbrechen” von
select()
von Linux auf Windows zu portieren und konnte bisher keine weiteren
Probleme damit feststellen.
Aktuell beschäftigt mich diese Routine wieder im GATE-Project, wo dieser Trick natürlich auch in der Socket-Group und dem Socket-Selector zum Einsatz kommt.