Wie ändere ich einen TCP-Socket so, dass er nicht blockiert?

Lesezeit: 5 Minuten

Benutzeravatar von Sachin Chourasiya
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.

  • 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

Benutzeravatar von Jeremy Friesner
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
}

Benutzeravatar von hookenz
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

Benutzeravatar von unwind
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

Sivas Benutzeravatar
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?

    • Haben Sie ein Design, das sich nicht um das Blockieren kümmert
    • Mit Auswählen
    • Verwenden von nicht blockierenden Sockets.
    • Verwendung von Multithreading oder Multitasking

  • 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");
    }

}

1408210cookie-checkWie ändere ich einen TCP-Socket so, dass er nicht blockiert?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy