Socket select() unterbrechen

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.


Wenn sich eine triviale Erkenntnis mit Dummheit in der Interpretation paart, dann gibt es in der Regel Kollateralschäden in der Anwendung.
frei zitiert nach A. Van der Bellen
... also dann paaren wir mal eine komplexe Erkenntnis mit Klugheit in der Interpretation!