2012-10-07 8 views
5

Ich schreibe einen Server in Linux, der gleichzeitige Lese-/Schreibvorgänge von mehreren Clients unterstützen muss. Ich möchte die Funktion verwenden, um die Lese-/Schreibverfügbarkeit zu verwalten.Welchen Vorteil hat die Verwendung von nicht blockierenden Sockeln bei der Funktion "Auswahl"?

Was ich nicht verstehe, ist dies: Angenommen, ich möchte warten, bis ein Socket Daten zum Lesen zur Verfügung hat. Die Dokumentation für select besagt, dass es blockiert, bis Daten zum Lesen verfügbar sind, und dass die Lesefunktion nicht blockiert wird.

Also wenn ich Select verwenden und ich weiß, dass die Lesefunktion nicht blockieren wird, warum müsste ich meine Sockets auf nicht blockierende setzen?

Antwort

6

Es kann Fälle geben, in denen ein Socket als bereit gemeldet wird, aber wenn Sie es überprüfen, ändert sich der Status.

Eines der guten Beispiele ist die Annahme von Verbindungen. Wenn eine neue Verbindung eintrifft, wird ein abhörender Socket als bereit zum Lesen gemeldet. Wenn Sie anrufen, um zu akzeptieren, kann die Verbindung von der anderen Seite geschlossen werden, bevor überhaupt etwas gesendet wird und bevor wir accept anriefen. Natürlich ist die Handhabung dieses Falls vom Betriebssystem abhängig, aber es ist möglich, dass accept einfach blockiert, bis eine neue Verbindung hergestellt wird, was dazu führt, dass unsere Anwendung auf unbestimmte Zeit wartet, was die Verarbeitung anderer Sockets verhindert. Wenn sich Ihr abhörender Socket in einem nicht blockierenden Modus befindet, wird dies nicht passieren und Sie werden oder einen anderen Fehler erhalten, aber accept wird sowieso nicht blockieren.

Einige Kernel hatten (ich hoffe, es ist jetzt behoben) einen interessanten Fehler mit UDP und select. Wenn ein Datagramm eintrifft, wacht select mit dem Socket auf, wobei das Datagramm als bereit zum Lesen markiert ist. Die Datagramm-Prüfsummenvalidierung wird verschoben, bis ein Benutzercode recvfrom (oder eine andere API, die UDP-Datagramme empfangen kann) aufruft. Wenn der Code recvfrom aufruft und der Validierungscode eine Prüfsummenabweichung feststellt, wird ein Datagramm einfach gelöscht und recvfrom wird bis zum Eintreffen eines nächsten Datagramms blockiert. Eines der Patches zur Behebung dieses Problems (zusammen mit der Problembeschreibung) finden Sie unter here.

2

Einer der Vorteile ist, dass es alle Programmierfehler auffängt, die Sie machen, denn wenn Sie versuchen, einen Socket zu lesen, der Sie normalerweise blockiert, erhalten Sie stattdessen EWOULDBLOCK. Bei anderen Objekten als Sockets kann sich das genaue API-Verhalten ändern, siehe http://www.scottklement.com/rpg/socktut/nonblocking.html.

+0

Aha, danke dafür. :) – CaptainCodeman

1

Dies klingt snarky, aber es ist nicht. Der beste Grund, sie nicht blockierend zu machen, ist, dass Sie nicht blocken.

Denken Sie darüber nach. select() sagt Ihnen, es gibt etwas zu lesen, aber Sie wissen nicht, wie viel. Könnte 2 Bytes sein, könnte 2.000 sein. In den meisten Fällen ist es effizienter, alle vorhandenen Daten zu löschen, bevor man zu select zurückkehrt. Sie geben also eine While-Schleife zum Lesen ein

Was passiert beim letzten Lesen, wenn nichts mehr zu lesen ist? Wenn der Sockel nicht blockierungsfrei ist, werden Sie blockieren und dadurch (zumindest teilweise) den Punkt select() vereiteln.

3

Abgesehen von den von anderen erwähnten Kernel-Fehlern liegt ein anderer Grund für die Auswahl nicht blockierender Sockets auch bei einer Polling-Schleife darin, dass sie eine höhere Leistung bei schnell ankommenden Daten ermöglicht. Denken Sie darüber nach, was passiert, wenn ein blockierender Socket als "lesbar" markiert wird. Sie haben keine Ahnung, wie viele Daten angekommen sind, sodass Sie sie nur einmal sicher lesen können.Dann müssen Sie zur Ereignisschleife zurückkehren, damit Ihr Poller überprüft, ob der Socket noch lesbar ist. Das bedeutet, dass Sie für jeden einzelnen Lese- oder Schreibzugriff auf den Socket zwei mindestens zwei Systemaufrufe ausführen müssen: den select, um Ihnen zu sagen, dass Sie sicher lesen können, und den Lese-/Schreib-Aufruf selbst.

Mit nicht blockierenden Sockets können Sie die unnötigen Anrufe nach select nach dem ersten überspringen. Wenn ein Socket von select als lesbar gekennzeichnet ist, haben Sie die Möglichkeit, von ihm zu lesen, solange es Daten zurückgibt, was eine schnellere Verarbeitung schneller Datenbursts ermöglicht.

+0

Danke, sehr guter Punkt, ich wusste nicht, dass der Versuch zu lesen wäre schneller als ein anderer wählen. – CaptainCodeman

Verwandte Themen