Wie macht man eine Steckdose blockierungsfrei?
Ich bin mir der bewusst fcntl()
funktionieren, aber ich habe gehört, dass es nicht immer zuverlässig ist.
Sachin Chourasiya
Wie macht man eine Steckdose blockierungsfrei?
Ich bin mir der bewusst fcntl()
funktionieren, aber ich habe gehört, dass es nicht immer zuverlässig ist.
Jeremy Friesner
fcntl()
hat bei mir immer zuverlässig funktioniert. In jedem Fall ist hier die Funktion, die ich zum Aktivieren / Deaktivieren der Blockierung eines Sockets verwende:
#include <fcntl.h>
/** Returns true on success, or false if there was an error */
bool SetSocketBlockingEnabled(int fd, bool blocking)
{
if (fd < 0) return false;
#ifdef _WIN32
unsigned long mode = blocking ? 0 : 1;
return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false;
#else
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) return false;
flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
#endif
}
Hakenz
Sie sind falsch informiert fcntl()
nicht immer zuverlässig. Es ist unwahr.
Um einen Socket als nicht blockierend zu markieren, ist der Code so einfach wie:
// where socketfd is the socket you want to make non-blocking
int status = fcntl(socketfd, F_SETFL, fcntl(socketfd, F_GETFL, 0) | O_NONBLOCK);
if (status == -1){
perror("calling fcntl");
// handle the error. By the way, I've never seen fcntl fail in this way
}
Unter Linux, auf Kerneln > 2.6.27 können Sie Sockets auch von vornherein mit nicht-blockierend erstellen socket()
und accept4()
.
z.B
// client side
int socketfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
// server side - see man page for accept4 under linux
int socketfd = accept4( ... , SOCK_NONBLOCK);
Es spart ein wenig Arbeit, ist aber weniger portabel, also neige ich dazu, es mit einzustellen fcntl()
.
oops, habe gerade festgestellt, dass dies eine wirklich alte Frage ist. Ahh, ich denke, es ist Zeit, eine aktualisierte Antwort zu geben.
– Hookenz
11. März 2014 um 23:55 Uhr
vielleicht alt, aber immer noch hilfreich. Ihre Antwort scheint genau das zu sein, wonach ich gesucht habe.
– Bart Friedrichs
1. Oktober 2014 um 15:00 Uhr
Ist es nicht möglich, dass Ihr internes fcntl
scheitert vor dem externen fcntl
scheitert?
– CMCDragonkai
21. Januar 2017 um 13:40 Uhr
Abhängig davon, wie Sie Ihren Code schreiben, können Sie möglicherweise Rennbedingungen einrichten, wenn Sie anrufen fcntl
nachdem Sie den Socket erstellt haben …. deshalb die SOCK_NONBLOCK
-Flag wurde hinzugefügt, sodass Sie einen Socket atomar als nicht blockierend erstellen können
– Pferdemensch
18. März 2018 um 9:57 Uhr
Hüten Sie sich davor fcntl(socketfd, F_GETFL, 0)
kann fehlschlagen, überprüfen Sie also den Rückgabewert, bevor Sie ihn an die Ausgabe übergeben
– Schote
14. März 2019 um 10:53 Uhr
entspannen
Was meinst du mit “nicht immer zuverlässig”? Wenn es dem System gelingt, Ihren Socket nicht-blockierend einzustellen, wird es nicht-blockierend sein. Socket-Operationen werden zurückgegeben EWOULDBLOCK
wenn sie blockieren würden, müssen sie blockieren (z. B. wenn der Ausgabepuffer voll ist und Sie send/write zu oft aufrufen).
Dieser Forenthread hat ein paar gute Punkte bei der Arbeit mit nicht blockierenden Anrufen.
Ich denke nicht, dass dies eine gute Antwort ist. Sie sagen ihm, dass es zuverlässig sein sollte, und posten dann einen Forenthread, der schnell veraltet sein kann. Nur meine Meinung, aber jemand mit Ihrem Vertreter, von dem ich gedacht hätte, dass er nachdenklich genug wäre, um eine gründlichere Antwort zu geben als einen faulen Link und einen schnellen Kommentar.
– Hookenz
11. März 2014 um 23:22 Uhr
@ Matt Entschuldigung für die Enttäuschung. Bitte beachten Sie, dass diese Antwort viereinhalb Jahre alt ist. Ich denke, meine Antwort zeigt meine Frustration über den Mangel an Details der Frage. Es ist schwer zu argumentieren mit “Ich habe gehört, dass es nicht immer zuverlässig ist, es auf die offensichtliche Weise zu tun”. Ich denke immer noch, bin mir nicht sicher, wie ich das verbessern kann.
– abschalten
12. März 2014 um 6:59 Uhr
Ja, mir wurde später klar, wie alt die Frage war. Ich dachte, es sei neu, weil jemand anderes es aktualisiert hat und es in der Aktivitätsliste auftauchte … oops. egal.
– Hookenz
12. März 2014 um 7:12 Uhr
Hinweis aus den Manpages: „POSIX.1-2001 lässt beide Fehler zu [EAGAIN or EWOULDBLOCK] in diesem Fall zurückgegeben werden und erfordert nicht, dass diese Konstanten denselben Wert haben, daher sollte eine portable Anwendung nach beiden Möglichkeiten suchen.”
– sij
1. September 2020 um 20:51 Uhr
Shiva
fcntl()
oder ioctl()
werden verwendet, um die Eigenschaften für Dateistreams festzulegen. Wenn Sie diese Funktion verwenden, um einen Socket nicht blockierend zu machen, funktionieren Sie wie accept()
, recv()
usw., die von Natur aus blockieren, geben Fehler und zurück errno
eingestellt wäre EWOULDBLOCK
. Sie können Dateideskriptorsätze abfragen, um Sockets abzufragen.
Unter Linux und BSD können Sie den Socket direkt im nicht blockierenden Modus erstellen (https://www.man7.org/linux/man-pages/man7/socket.7.html):
int fd = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK | SOCK_CLOEXEC, res->ai_protocol);
if (fd == -1) {
perror("socket");
return -1;
}
Beim Annehmen von Verbindungen können Sie die verwenden accept4
Funktion zum direkten Akzeptieren neuer Verbindungen im nicht blockierenden Modus (https://man7.org/linux/man-pages/man2/accept.2.html):
int fd = accept4(lfd, NULL, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (fd == -1) {
perror("accept4");
return -1;
}
Ich weiß nicht, warum die akzeptierte Antwort dies nicht erwähnt.
accept4() ist eine Nicht-Standard-Linux-Erweiterung.
– stn
19. Mai 2021 um 9:34 Uhr
Ich weiß, es ist eine alte Frage, aber für alle, die hier bei Google landen und nach Informationen zum Umgang mit blockierenden und nicht blockierenden Sockets suchen, finden Sie hier eine ausführliche Erklärung der verschiedenen Möglichkeiten, wie mit den E / A-Modi von Sockets umgegangen werden kann – http://dwise1.net/pgm/sockets/blocking.html.
Kurze Zusammenfassung:
Warum blockieren Sockets?
Was sind die grundlegenden Programmiertechniken für den Umgang mit blockierenden Sockets?
accept4() ist eine Nicht-Standard-Linux-Erweiterung.
– stn
19. Mai 2021 um 9:34 Uhr
Wenn Sie sich ändern möchten Buchse auf nicht blockierend genau annehmen() zu NICHT-blockierend Staat dann
int flags=fcntl(master_socket, F_GETFL);
fcntl(master_socket, F_SETFL,flags| O_NONBLOCK); /* Change the socket into non-blocking state F_SETFL is a command saying set flag and flag is 0_NONBLOCK */
while(1){
if((newSocket = accept(master_socket, (struct sockaddr *) &address, &addr_size))<0){
if(errno==EWOULDBLOCK){
puts("\n No clients currently available............ \n");
continue;
}
}else{
puts("\nClient approched............ \n");
}
}
Ich muss nur einen TCP-Socket in einen nicht blockierenden Socket konvertieren.
– Sachin Chourasiya
9. Oktober 2009 um 12:35 Uhr
Es ist nur unzuverlässig, wenn Sie keine Fehlerprüfung durchführen und davon ausgehen, dass es immer erfolgreich ist. 🙂
– Qix – MONICA WURDE MISSHANDELT
10. November 2016 um 6:45 Uhr