2009-10-09 8 views
27

Wie macht man einen Sockel nicht blockierend?Wie ändere ich einen TCP-Socket als nicht blockierend?

Ich bin mir der fcntl() Funktion bewusst, aber ich habe gehört, dass es nicht immer zuverlässig ist.

+1

Ich muss nur einen TCP-Socket in nicht blockierende Socket konvertieren. –

+1

Es ist nur unzuverlässig, wenn Sie keine Fehlerprüfung durchführen und davon ausgehen, dass es immer erfolgreich ist. :) – Qix

Antwort

19

Was meinen Sie mit "nicht immer zuverlässig"? Wenn es dem System gelingt, den Socket nicht blockierungsfrei zu setzen, blockiert es nicht. Socket-Operationen geben zurück, wenn sie Blockierung blockieren würden (z. B. wenn der Ausgabepuffer voll ist und Sie zu oft send/write aufrufen).

This forum thread hat ein paar gute Punkte, wenn Sie mit nicht blockierenden Anrufen arbeiten.

+12

Ich denke nicht, dass dies eine gute Antwort ist. Sie sagen ihm, dass es zuverlässig sein sollte, dann poste einen Forum-Thread, der schnell veraltet werden kann. Nur meine Meinung, aber jemand mit Ihrer Repräsenz, die ich gedacht hätte, wäre nachdenklich genug, um eine gründlichere Antwort als eine faule Verbindung und einen schnellen Kommentar zu geben. – Matt

+4

@Matt Entschuldigung zu enttäuschen. Bitte beachten Sie, dass diese Antwort viereinhalb Jahre alt ist. Ich denke, meine Antwort zeigt meine Frustration über den Mangel an Details.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, nicht sicher, wie ich das verbessern könnte. – unwind

+0

Ja, mir wurde später klar, wie alt die Frage war. Ich dachte, es wäre neu, weil jemand anderes es aktualisiert hat und es in der Aktivitätsliste aufgetaucht ist ... oops. Vergiss es. – Matt

12

fcntl() oder ioctl() werden verwendet, um die Eigenschaften für Dateiströme festzulegen. Wenn Sie diese Funktion verwenden, um einen Socket nicht blockierend zu machen, werden Funktionen wie accept(), recv() und usw., die in der Natur blockieren, einen Fehler zurückgeben, und errno wird auf gesetzt. Sie können Dateideskriptor-Sets abfragen, um nach Sockets abzufragen.

+0

Gibt es eine andere Möglichkeit, einen TCPIP in einen NON BLOCKING-Socket zu konvertieren. Ich möchte nicht auf diese Methoden verlassen, kann aufgrund meiner Erfahrungen in der Vergangenheit sein –

+8

Das ** ist ** der Weg, um einen Sockel zu non-blocking zu konvertieren. Wenn Sie sich auf Ihre "vergangenen Erfahrungen" beschränken können und warum Sie überzeugt sind, dass dies nicht funktioniert, können wir Ihnen vielleicht helfen. –

0

Die beste Methode zum Festlegen eines Sockets als nicht blockierend in C ist die Verwendung von ioctl. Ein Beispiel, wo ein akzeptierter Socket nicht blockierend gesetzt folgt:

long on = 1L; 
unsigned int len; 
struct sockaddr_storage remoteAddress; 
len = sizeof(remoteAddress); 
int socket = accept(listenSocket, (struct sockaddr *)&remoteAddress, &len) 
if (ioctl(socket, (int)FIONBIO, (char *)&on)) 
{ 
    printf("ioctl FIONBIO call failed\n"); 
} 
+0

Ist das nicht asynchroner Socket und nicht blockierend? – JuliandotNut

+0

In C/C++, seine eigentlich nicht blockierende Verwendung von Standard-Sockets/Winsock. –

1

Im Allgemeinen können Sie den gleichen Effekt erzielen, indem normale mit IO und Multiplexen mehr IO blockieren Operationen mit select(2), poll(2) oder einem anderen Systemaufrufe, die auf Ihrem System verfügbar sind.

Siehe The C10K problem für den Vergleich von Ansätzen für skalierbare IO-Multiplexing.

+0

Nicht unter POSIX, als 'man select' Zustände im BUG-Bereich, kann' select' den Socket als Read-Read-Datei angeben, aber dann kann 'Read' blockieren. Es ist also nicht das Gleiche. – zoska

+0

Wir sind jetzt weit über die C10K-Probleme hinausgekommen. – Matt

+0

syscall poll (2) ist O (n), epoll (2) ist O (1) das ist nur lösung zu C10K + – Anatoly

64

fcntl() hat immer zuverlässig für mich gearbeitet. In jedem Fall ist hier die Funktion ermogliche verwenden, um/deaktivieren auf einem Socket blockiert:

#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 
} 
+0

Ich denke, du beabsichtigst #include statt #import. – tambre

+0

Ich reparierte es, danke. –

+0

(Flags <0) ist falsch. Nur '-1' bedeutet Fehler, andere negative Ganzzahlwerte können gültige Flag-Bitmasken sein. –

33

Sie fcntl() falsch informiert über nicht immer zuverlässig. Es ist unwahr.

Um eine Socket als nicht-blockierende zu markieren ist, den 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 Kernel> 2.6.27 Sie auch Steckdosen non-blocking von vornherein socket() und accept4() Verwendung erstellen können .

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, aber weniger tragbar, so neige ich dazu, es zu setzen mit fcntl().

+0

oops, habe gerade gemerkt, dass das eine wirklich alte Frage ist. Ahh, ich denke, es ist Zeit, eine aktualisierte Antwort zu geben. – Matt

+3

vielleicht alt, aber immer noch hilfreich. Ihre Antwort scheint genau das zu sein, wonach ich gesucht habe. –

+0

Ist es nicht möglich, dass Ihr interner 'fcntl' fehlschlägt, bevor der externe' fcntl' fehlschlägt? – CMCDragonkai

Verwandte Themen