Share via


Windows Sockets 1.1 Blockierungsroutinen und EINPROGRESS

Ein hauptproblem beim Portieren von Anwendungen aus einer Berkeley Sockets-Umgebung in eine Windows-Umgebung ist das Blockieren; Dies bedeutet, dass eine Funktion aufgerufen wird, die erst zurückgegeben wird, wenn der zugeordnete Vorgang abgeschlossen ist. Ein Problem tritt auf, wenn der Vorgang beliebig lange dauert: Ein Beispiel ist eine recv-Funktion , die blockiert, bis Daten vom Peersystem empfangen wurden. Das Standardverhalten innerhalb des Berkeley Sockets-Modells besteht darin, dass ein Socket im Blockierungsmodus ausgeführt wird, es sei denn, der Programmierer fordert explizit an, dass Vorgänge als Nichtblockierung behandelt werden. Windows Sockets 1.1-Umgebungen konnten keine präemptive Planung annehmen. Daher wurde dringend empfohlen, dass Programmierer die nicht blockierenden (asynchronen) Vorgänge verwenden, wenn dies mit Windows Sockets 1.1 überhaupt möglich ist. Da dies nicht immer möglich war, wurden die im Folgenden beschriebenen Pseudoblockierungseinrichtungen bereitgestellt.

Hinweis

Windows Sockets 2 wird nur auf präemptiven 32-Bit-Betriebssystemen ausgeführt, bei denen Deadlocks kein Problem darstellen. Für Windows Sockets 1.1 empfohlene Programmierpraktiken sind in Windows Sockets 2 nicht erforderlich.

 

Selbst bei einem blockierenden Socket werden einige Funktionen wie bind, getsockopt und getpeername sofort abgeschlossen. Es gibt keinen Unterschied zwischen einem Blockierungs- und einem Nichtblockierungsvorgang für diese Funktionen. Andere Vorgänge, z. B. recv, können je nach Transportbedingungen sofort abgeschlossen werden oder eine beliebige Zeit in Anspruch nehmen. Wenn sie auf einen blockierenden Socket angewendet werden, werden diese Vorgänge als blockierende Vorgänge bezeichnet. Die folgenden Funktionen können blockieren:

Bei 16-Bit-Windows Sockets 1.1 wird ein Blockierungsvorgang, der nicht sofort abgeschlossen werden kann, wie folgt durch Pseudoblockierung behandelt.

Der Dienstanbieter initiiert den Vorgang, gibt dann eine Schleife ein, in der er alle Windows-Nachrichten sendet (sodass der Prozessor ggf. an einen anderen Thread weitergeleitet wird), und überprüft dann, ob die Windows Sockets-Funktion abgeschlossen ist. Wenn die Funktion abgeschlossen wurde oder WSACancelBlockingCall aufgerufen wurde, wird die blockierende Funktion mit einem entsprechenden Ergebnis abgeschlossen.

Ein Dienstanbieter muss die Installation einer blockierenden Hookfunktion zulassen, die keine Nachrichten verarbeitet, um die Möglichkeit von Erneuteinführungsnachrichten zu vermeiden, während ein Blockierungsvorgang aussteht. Die einfachste blockende Hookfunktion würde FALSE zurückgeben. Wenn eine Windows Sockets-DLL von Meldungen für den internen Betrieb abhängt, kann sie PeekMessage(hMyWnd...) ausführen, bevor der Anwendungsblockierungs-Hook ausgeführt wird, sodass sie ihre Meldungen abrufen kann, ohne den Rest des Systems zu beeinträchtigen.

Wenn in einer 16-Bit-Windows Sockets 1.1-Umgebung eine Windows-Nachricht für einen Prozess empfangen wird, für den ein Blockierungsvorgang ausgeführt wird, besteht das Risiko, dass die Anwendung versucht, einen weiteren Windows Sockets-Aufruf auszugeben. Aufgrund der Schwierigkeiten, diese Bedingung sicher zu verwalten, unterstützt Windows Sockets 1.1 dieses Anwendungsverhalten nicht. Eine Anwendung darf nicht mehr als einen geschachtelten Windows Sockets-Funktionsaufruf ausführen. Für einen bestimmten Vorgang ist nur ein ausstehender Funktionsaufruf zulässig. Die einzigen Ausnahmen sind zwei Funktionen, die zur Unterstützung des Programmierers in dieser Situation bereitgestellt werden: WSAIsBlocking und WSACancelBlockingCall.

Die WSAIsBlocking-Funktion kann jederzeit aufgerufen werden, um zu bestimmen, ob ein blockierender Windows Sockets 1.1-Aufruf ausgeführt wird. Ebenso kann die WSACancelBlockingCall-Funktion jederzeit aufgerufen werden, um einen laufenden Blockierungsaufruf abzubrechen. Bei allen anderen Schachtelungen von Windows Sockets-Funktionen tritt der Fehler WSAEINPROGRESS auf.

Es sollte betont werden, dass diese Einschränkung sowohl für blockierende als auch für nicht blockierende Vorgänge gilt. Für Windows Sockets 2-Anwendungen, die Version 2.0 oder höher zum Zeitpunkt des Aufrufs von WSAStartup aushandeln, wird die Schachtelung von Vorgängen nicht eingeschränkt. Vorgänge können unter seltenen Umständen geschachtelt werden, z. B. während eines WSAAccept-Rückrufs mit bedingter Akzeptanz oder wenn ein Dienstanbieter wiederum eine Windows Sockets 2-Funktion aufruft.

Obwohl dieser Mechanismus für einfache Anwendungen ausreichend ist, kann er die komplexen Nachrichtenverteilungsanforderungen von komplexeren Anwendungen (z. B. anwendungen, die das MDI-Modell verwenden) nicht unterstützen. Für solche Anwendungen enthält die Windows Sockets-API die Funktion WSASetBlockingHook, mit der die Anwendung eine spezielle Routine angeben kann, die anstelle der in der vorherigen Diskussion beschriebenen Standardroutine für die Nachrichtenverteilung aufgerufen werden kann.

Der Windows Sockets-Anbieter ruft den blockierenden Hook nur auf, wenn alle folgenden Punkte zutreffen:

  • Die Routine ist eine, die als blockfähig definiert ist.
  • Der angegebene Socket ist ein blockierende Socket.
  • Die Anforderung kann nicht sofort abgeschlossen werden.

Ein Socket ist standardmäßig auf blockieren festgelegt, aber die ioctlsocket-Funktion mit der FIONBIO-IOCTL oder der WSAAsyncSelect-Funktion kann einen Socket auf den Nichtblockierungsmodus festlegen.

Der blockierende Hook wird nie aufgerufen, und die Anwendung muss sich nicht mit den Problemen befassen, die der blockierende Hook einführen kann, wenn eine Anwendung die folgenden Richtlinien befolgt:

Wenn eine Windows Sockets 1.1-Anwendung einen asynchronen oder nicht blockierenden Vorgang aufruft, der einen Zeiger auf ein Speicherobjekt (z. B. einen Puffer oder eine globale Variable) als Argument verwendet, liegt es in der Verantwortung der Anwendung sicherzustellen, dass das Objekt während des vorgangs für Windows Sockets verfügbar ist. Die Anwendung darf keine Windows-Funktion aufrufen, die sich auf die Zuordnung oder die Adressierbarkeit des betreffenden Arbeitsspeichers auswirken könnte.