Socket: MSG_PEEK mit und ohne O_NONBLOCK
-
Hallo Leute,
also ich hab folgendes Problem: je nachdem auf welcher Maschine mein Programm kompiliert wird, werden entweder Sockets mit O_NONBLOCK verwendet oder eben blockierende Sockets ohne dieses Flag.
Ich möchte nun herausfinden, ob mein Socket Daten zum Lesen bereit hält, oder nicht. Bei nicht blockierenden Sockets sollte das wunderbar mit recv(X, Y, Z, MSG_PEEK) funktionieren. Aber wie mache ich das mit blockierenden? Auch mit MSG_PEEK wird recv() blockieren, was ich aber vermeiden will.
Welche Möglichkeiten hab ich denn? Schonmal vielen Dank im Voraus!
-
Normalerweise schaut man mit select(), poll() oder epoll(), ob Daten vorliegen.
-
Genau darauf "baut mein Problem auf". Normalerweise nutze ich epoll um rauszufinden ob Daten vorliegen. Da nutze ich Sockets mit O_NONBLOCK.
Sockets mit Daten werden an einen "Worker-Thread" weitergegeben, der jetzt alle Daten vollständig auslesen muss (epoll ist edge-triggered eingestellt).
Fall ich aber auf einer Maschine bin, auf der epoll nicht zur Verfügung steht, wird poll anstatt epoll verwendet. Leider ist poll unter Linux nicht POSIX konform und reagiert nicht so:
The poll() function shall not be affected by the O_NONBLOCK flag.
Siehe POSIX poll.
Sondern es reagiert auf O_NONBLOCK Sockets mit sofortigem return aus der Funktion. Deswegen nutze ich mit poll Sockets ohne O_NONBLOCK, aber würde gerne im Worker-Thread trotzdem alle Daten abrufen (falls mehrere vorhanden sind).
Bei epoll und O_NONBLOCK ists klar, da returned recv() ja immer sofort, aber wie mache ich das mit poll ohne diese Flag?
-
Sondern es reagiert auf O_NONBLOCK Sockets mit sofortigem return aus der Funktion.
Dann ist dein Linux kaputt.
-
Sehr sinnvoller Beitrag! Musstest du dich unbedingt hier verbal übergeben?
-
Kannst Du nicht als Workaroung O_NONBLOCK vor dem peek setzen und danach wieder löschen (fcntl)?
-
Man bin ich dämlich, natürlich...
Manchmal seh ich den Wald vor lauter Bäumen nicht mehr.
Danke!
-
Jetzt versteh ich warum ich gedacht habe, dass poll() auf O_NONBLOCK reagiert!
Folgende Implementierung:
- Netzwerk-Thread der mittels epoll (oder poll) alle Sockets auf Daten überprüft
- fall Daten vorhanden, wird ein Worker-Thread darüber informiert
- Worker-Thread arbeitet die Nachrichten ab, sobald er "die Zeit findet"-> epoll ist edge-triggered, also alle Nachrichten über die einmal informiert wurde, wird beim nächsten Aufruf ignoriert
-> poll ist level-triggered, also sobald Nachrichten am Socket anliegen, wird darüber informiert (egal ob das schonmal geschehen ist)Poll returned so lange sofort, bis mein Worker-Thread die Daten abholen konnte. Epoll hingegen tut das nicht. Daher dachte ich, poll reagiert irgendwie auf O_NONBLOCK, was aber nicht der Fall ist