Überlappte E/A-Buchse im Vergleich zum Blockierungs-/Nichtblockierungsmodus


Zusammenfassung


In diesem Artikel wird der Unterschied zwischen dem überlappenden E/A-Attribut eines Sockets und dem blockierenden oder nicht blockierenden Modus des Sockets erläutert.

Weitere Informationen


Wenn ein Socket erstellt wird, handelt es sich standardmäßig um einen blockierenden Socket. Sie können den Befehl FIONBIO im ioctlsocket-API-Aufruf WSAEventSelect oder WSAAysncSelect verwenden, um den Socketmodus von blockierend in nicht blockierend zu ändern. Wenn ein Winsock-Aufruf nicht sofort abgeschlossen werden kann, schlägt der Aufruf fehl, und WSAGetLastError gibt einen WSAEWOULDBLOCK-Fehler zurück, wenn es sich um einen nicht blockierenden Socket handelt, oder der Aufruf blockiert, bis der Vorgang abgeschlossen ist, wenn es sich um einen blockierenden Socket handelt. Das überlappende E/A-Attribut des Sockets unterscheidet sich vom blockierenden oder nicht blockierenden Modus des Sockets. Obwohl die aktuelle Winsock-Implementierung überlappende E/A-Attribute für den nicht blockierenden Socketmodus erfordert, sind sie konzeptionell unabhängig, und ihr Programmiermodell ist ebenfalls unterschiedlich. Um einen Socket mit dem überlappenden E/A-Attribut zu erstellen, können Sie entweder die Socket-API oder die WSASocket-API mit dem WSA_FLAG_OVERLAPPED-Flagsatz verwenden. Wenn ein überlappender E/A-Vorgang nicht sofort abgeschlossen werden kann, schlägt der Aufruf fehl und WSAGetLastError oder GetLastError geben WSA_IO_PENDING oder ERROR_IO_PENDING zurück, was eigentlich der gleichen Definition wie WSA_IO_PENDING entspricht. Weitere Informationen finden Sie im folgenden Artikel in der Microsoft Knowledge Base:
179942 INFO: WSA_FLAG_OVERLAPPED wird für nicht blockierende Sockets benötigt
Bitte beachten Sie, dass nach dem Erstellen eines Sockets keine Möglichkeit mehr besteht, das überlappende Attribut des Sockets zu ändern. Sie können jedoch die setsockopt-API mit der Option SO_OPENTYPE für alle Sockethandles einschließlich eines INVALID_SOCKET aufrufen, um die überlappenden Attribute für alle aufeinanderfolgenden Socketaufrufe im gleichen Thread zu ändern. Der Standardwert für den SO_OPENTYPE-Optionswert ist 0, wodurch das überlappende Attribut festgelegt wird. Alle Optionswerte ungleich Null machen den Socket synchron und so, dass Sie keine Vervollständigungsfunktion verwenden können. Wenn Sie das überlappende E/A-Attribut eines Sockets festlegen, bedeutet dies nicht, dass der Socket einen überlappenden E/A-Vorgang ausführt. Wenn Sie z. B. NULL sowohl für die Vervollständigungsfunktion als auch für die überlappende Struktur in WSARecv und WSASend angeben oder einfach recv oder Sendefunktionen aufrufen, werden diese in blockierender Weise abgeschlossen. Um sicherzustellen, dass die E/A-Funktion überlappend ausgeführt wird, müssen Sie abhängig von der von Ihnen genutzten Funktion eine überlappende Struktur in Ihrer E/A-Funktion bereitstellen.

Überlappte E/A

In Winsock 1 erstellen Sie einen überlappenden Socket mithilfe der Socket-API und verwenden Win32-Datei-I/O-API-ReadFile, ReadFileEx, WriteFile, WriteFileEx, um überlappende E/A-Vorgänge für das Sockethandle auszuführen. In Winsock 2 erstellen Sie einen überlappenden Socket mit WSASocket mit dem WSA_FLAG_OVERLAPPED-Flag oder einfach mit der Socket-API. Sie können die oben genannten Win32-Datei-I/O-APIs oder Winsock 2 WSASend, WSASendTo, WSARecv und WSARecvFrom verwenden, um einen überlappenden E/A-Vorgang zu initiieren. Wenn Sie die Option SO_RCVBUF und SO_SNDBUF verwenden, um den TCP-Stack-Empfangs- und Sendepuffer null festzulegen, weisen Sie den TCP-Stack grundsätzlich an, E/A-Vorgänge direkt mithilfe des in Ihrem E/A-Aufruf bereitgestellten Puffers auszuführen. Zusätzlich zum nicht blockierenden Vorteil der überlappenden Socket-E/A ist der andere Vorteil eine bessere Leistung, da Sie eine Pufferkopie zwischen dem TCP-Stackpuffer und dem Benutzerpuffer für jeden E/A-Aufruf speichern. Sie müssen jedoch sicherstellen, dass Sie nicht auf den Benutzerpuffer zugreifen, sobald er für einen überlappenden Vorgang übermittelt wurde und bevor der überlappende Vorgang abgeschlossen ist. Um zu bestimmen, ob der überlappende E/A-Vorgang abgeschlossen ist, können Sie eine der folgenden Optionen verwenden:
  • Sie können ein Ereignishandle in einer überlappenden Struktur bereitstellen, die im E/A-Aufruf verwendet wird, und auf das Signal des Ereignishandles warten.
  • Verwenden Sie GetOverlappedResult oder WSAGetOverlappedResult, um den Status des überlappenden E/A-Vorgangs abzutun. Unter Windows NT können Sie NULL als Ereignishandle in der überlappenden Struktur angeben. Unter Windows 95 muss die überlappende Struktur jedoch ein manuelles Zurücksetzen von Ereignishandle enthalten. WSAGetOverlappedResult unter Windows 98 und Windows Millennium Edition (ME) wird so geändert, dass es sich wie Windows NT verhält und auch den Abschlussstatus mit einem NULL-Ereignishandle in der überlappenden Struktur abfragen kann.
  • Verwenden Sie ReadFileEx, WriteFileEx, WSARecv, WSARecvFrom, WSASend oder WSASendTo, und wählen Sie eine Vervollständigungsfunktion bereit, die aufgerufen werden soll, wenn der überlappende E/A-Vorgang abgeschlossen ist. Wenn Sie den Abschlussfunktionsansatz verwenden, müssen Sie irgendwann, nachdem Sie den überlappenden E/A-Vorgang ausgegeben haben, eine Win32-Wartefunktion oder eine WSA-Version der Wartefunktion ausgeben, um auf einem nicht signalisierten Handle zu warten, um den aktuellen Thread in einen warbaren Wartezustand zu versetzen. Wenn der überlappende E/A-Vorgang abgeschlossen ist, wird die Abschlussfunktion aufgerufen, die Wartefunktion gibt WAIT_IO_COMPLETION zurück, und Ihr warnbarer Wartethread wird aktiviert.
  • Verwenden Sie GetQueuedCompletionStatus, und ordnen Sie einen Socket zusammen mit dem überlappenden E/A-Attributsatz einem Windows NT-E/A-Vervollständigungsport (IOCP) zu. Mit IOCP müssen Sie keine Abschlussfunktion bereitstellen, auf einen Ereignishandle warten, um zu signalisieren, oder den Status des überlappenden Vorgangs abfragen. Nachdem Sie das IOCP erstellt und das überlappende Sockethandle zum IOCP hinzugefügt haben, können Sie den überlappenden Vorgang mithilfe einer der oben genannten E/A-APIs (außer recv, recvfrom, send oder sendto) starten. Sie haben Ihren Workerthreadblock in der GetQueuedCompletionStatus-API, die auf ein E/A-Abschlusspaket wartet. Wenn eine überlappende E/A abgeschlossen ist, kommt ein E/A-Vervollständigungspaket beim IOCP an, und GetQueuedCompletionStatus kehrt zurück. IOCP ist die Windows NT-Betriebssystemunterstützung für das Schreiben eines skalierbaren Servers mit hohem Durchsatz, der sehr einfachen Threading- und Blockierungscode für überlappende E/A-Vorgänge verwendet. Somit kann es einen erheblichen Leistungsvorteil bei der Verwendung überlappender Socket-E/A mit Windows NT-IOCPs geben.

Blockier- und Nichtblockierungsmodus

Wenn ein Socket erstellt wird, handelt es sich standardmäßig um einen blockierenden Socket. Schließen Sie unter Dematiermodus Socket-E/A-Vorgänge n-A-Betrieb alle Blockvorgänge an und akzeptieren Sie sie, bis der betreffende Vorgang abgeschlossen ist. Um den Socketbetriebsmodus vom Blockierungsmodus in den Nichtblockierungsmodus zu ändern, können Sie entweder WSAAsyncSelect, WSAEventSelect oder den Befehl FIONBIO im ioctlsocket-API-Aufruf verwenden. WSAAsyncSelect ordnet Socketbenachrichtigungen Windows-Nachrichten zu und ist das beste Modell für eine GUI-Anwendung mit einem threadierten Thread. WSAEventSelect verwendet WSAEnumNetworkEvents, um die Art der Socketbenachrichtigung für das Signalereignis zu bestimmen, und ordnet Socketbenachrichtigungen zu, indem ein Ereignis signalisiert wird. Dies ist ein nützliches Modell für Nicht-GUI-Anwendungen, denen eine Nachrichtenpumpe fehlt, z. B. eine Windows NT-Dienstanwendung. Der FiONBIO-Befehl im ioctlsocket-API-Aufruf versetzt den Socket ebenfalls in den nicht blockierenden Modus. Sie müssen jedoch den Status des Sockets mithilfe der ausgewählten API abfragen. Update: Das Festlegen von SO_RCVBUF auf Null mit überlappendem recv ist für Windows 2000 nicht erforderlich, wodurch die Daten direkt in den recv-Puffer der Anwendung kopiert werden können. Das Festlegen von SO_SNDBUF auf Null mit überlappendem Senden unter Windows 2000 hat immer noch den gleichen Vorteil, dass eine Speicherkopie gespeichert wird wie unter Windows NT 4.0. Es ist auch wichtig, dass die Anwendung mehrere ausstehende überlappende Sender oder recv-Sende ausgibt, wenn die Anwendung den entsprechenden Stapelpuffer auf 0 setzt.