Freigeben über


SIO_ACQUIRE_PORT_RESERVATION-Steuerelementcode

BESCHREIBUNG

Der SIO_ACQUIRE_PORT_RESERVATION-Steuerungscode ruft eine Laufzeitreservierung für einen Block von TCP- oder UDP-Ports ab.

Um diesen Vorgang auszuführen, rufen Sie die Funktion WSAIoctl oder WSPIoctl mit den folgenden Parametern auf.

int WSAIoctl(
  (socket) s,             // descriptor identifying a socket
  SIO_ACQUIRE_PORT_RESERVATION, // dwIoControlCode
  (LPVOID) lpvInBuffer,  // pointer to an INET_PORT_RANGE structure
  (DWORD) cbInBuffer,    // size, in bytes, of the input buffer
  (LPVOID) lpvOutBuffer,             // pointer to an INET_PORT_RESERVATION_INSTANCE structure
  (DWORD) cbOutBuffer,   // size, in bytes, of the output buffer
  (LPDWORD) lpcbBytesReturned,    // number of bytes returned
  (LPWSAOVERLAPPED) lpOverlapped,   // OVERLAPPED structure
  (LPWSAOVERLAPPED_COMPLETION_ROUTINE) lpCompletionRoutine,  // completion routine
);
int WSPIoctl(
  (socket) s,             // descriptor identifying a socket
  SIO_ACQUIRE_PORT_RESERVATION, // dwIoControlCode
  (LPVOID) lpvInBuffer,  // pointer to an INET_PORT_RANGE structure
  (DWORD) cbInBuffer,    // size, in bytes, of the input buffer
  (LPVOID) lpvOutBuffer,             // pointer to a INET_PORT_RESERVATION_INSTANCE structure
  (DWORD) cbOutBuffer,   // size, in bytes, of the output buffer
  (LPDWORD) lpcbBytesReturned,    // number of bytes returned
  (LPWSAOVERLAPPED) lpOverlapped,   // OVERLAPPED structure
  (LPWSAOVERLAPPED_COMPLETION_ROUTINE) lpCompletionRoutine,  // completion routine
  (LPWSATHREADID) lpThreadId,   // a WSATHREADID structure
  (LPINT) lpErrno   // a pointer to the error code.
);

Parameter

s

Ein Deskriptor, der einen Socket identifiziert.

dwIoControlCode

Der Steuerelementcode für den Vorgang. Verwenden Sie für diesen Vorgang SIO_ACQUIRE_PORT_RESERVATION .

lpvInBuffer

Ein Zeiger auf den Eingabepuffer. Dieser Parameter enthält einen Zeiger auf eine INET_PORT_RANGE-Struktur , die die Startpunktnummer und die Anzahl der zu reservierenden Ports angibt.

cbInBuffer

Die Größe des Eingabepuffers in Bytes. Dieser Parameter sollte die Größe der INET_PORT_RANGE-Struktur aufweisen.

lpvOutBuffer

Ein Zeiger auf den Ausgabepuffer. Bei erfolgreicher Ausgabe enthält dieser Parameter einen Zeiger auf eine INET_PORT_RESERVATION_INSTANCE-Struktur .

cbOutBuffer

Die Größe des Ausgabepuffers in Bytes. Dieser Parameter muss mindestens die Größe der INET_PORT_RESERVATION_INSTANCE-Struktur aufweisen.

lpcbBytesReturned

Ein Zeiger auf eine Variable, die die Größe der im Ausgabepuffer gespeicherten Daten in Bytes empfängt.

Wenn der Ausgabepuffer zu klein ist, schlägt der Aufruf fehl, WSAGetLastError gibt WSAEINVAL zurück, und der parameter lpcbBytesReturned verweist auf den DWORD-Wert 0.

Wenn lpOverlappedNULL ist, kann der DWORD-Wert , auf den der lpcbBytesReturned-Parameter verweist, der bei einem erfolgreichen Aufruf zurückgegeben wird, nicht null sein.

Wenn der lpOverlapped-Parameter für überlappende Sockets nicht NULL ist, werden Vorgänge initiiert, die nicht sofort abgeschlossen werden können, und der Abschluss wird zu einem späteren Zeitpunkt angezeigt. Der DWORD-Wert , auf den der zurückgegebene Parameter lpcbBytesReturned verweist, kann null sein, da die Größe der gespeicherten Daten erst bestimmt werden kann, wenn der überlappende Vorgang abgeschlossen ist. Der endgültige Abschluss status kann abgerufen werden, wenn die entsprechende Vervollständigungsmethode signalisiert wird, wenn der Vorgang abgeschlossen ist.

lpvOverlapped

Ein Zeiger auf eine WSAOVERLAPPED-Struktur .

Wenn Socket s ohne das überlappende Attribut erstellt wurde, wird der lpOverlapped-Parameter ignoriert.

Wenn s mit dem überlappenden Attribut geöffnet wurde und der lpOverlapped-Parameter nicht NULL ist, wird der Vorgang als überlappender (asynchroner) Vorgang ausgeführt. In diesem Fall muss der lpOverlapped-Parameter auf eine gültige WSAOVERLAPPED-Struktur verweisen.

Bei überlappenden Vorgängen wird die WSAIoctl - oder WSPIoctl-Funktion sofort zurückgegeben, und die entsprechende Abschlussmethode wird nach Abschluss des Vorgangs signalisiert. Andernfalls wird die Funktion erst zurückgegeben, wenn der Vorgang abgeschlossen wurde oder ein Fehler auftritt.

lpCompletionRoutine

Typ: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

Ein Zeiger auf die Abschlussroutine, die aufgerufen wird, wenn der Vorgang abgeschlossen wurde (bei nicht überlappenden Sockets ignoriert).

lpThreadId

Ein Zeiger auf eine WSATHREADID-Struktur , die vom Anbieter in einem nachfolgenden Aufruf von WPUQueueApc verwendet werden soll. Der Anbieter sollte die referenzierte WSATHREADID-Struktur (nicht den Zeiger auf dieselbe) speichern, bis die WPUQueueApc-Funktion zurückgegeben wird.

Hinweis Dieser Parameter gilt nur für die WSPIoctl-Funktion .

lpErrno

Ein Zeiger auf den Fehlercode.

Hinweis Dieser Parameter gilt nur für die WSPIoctl-Funktion .

Rückgabewert

Wenn der Vorgang erfolgreich abgeschlossen wird, gibt die WSAIoctl - oder WSPIoctl-Funktion null zurück.

Wenn der Vorgang fehlschlägt oder aussteht, gibt die WSAIoctl - oder WSPIoctl-FunktionSOCKET_ERROR zurück. Rufen Sie WSAGetLastError auf, um erweiterte Fehlerinformationen zu erhalten.

Fehlercode Bedeutung
WSA_IO_PENDING Überlappender E/A-Vorgang wird ausgeführt. Dieser Wert wird zurückgegeben, wenn ein überlappender Vorgang erfolgreich initiiert wurde und der Abschluss zu einem späteren Zeitpunkt angegeben wird.
WSA_OPERATION_ABORTED Der E/A-Vorgang wurde wegen eines Threadendes oder einer Anwendungsanforderung abgebrochen. Dieser Fehler wird zurückgegeben, wenn ein überlappender Vorgang aufgrund des Schließens des Sockets oder der Ausführung des SIO_FLUSH IOCTL-Befehls abgebrochen wurde.
WSAEFAULT Das System hat beim Versuch, ein Zeigerargument in einem Aufruf zu verwenden, eine ungültige Zeigeradresse erkannt. Dieser Fehler wird zurückgegeben, wenn die Parameter lpvInBuffer, lpvoutBuffer, lpcbBytesReturned, lpOverlapped oder lpCompletionRoutine nicht vollständig in einem gültigen Teil des Benutzeradressraums enthalten sind.
WSAEINPROGRESS Ein Blockierungsvorgang wird momentan ausgeführt. Dieser Fehler wird zurückgegeben, wenn die Funktion aufgerufen wird, wenn ein Rückruf ausgeführt wird.
WSAEINTR Ein blockierender Vorgang wurde durch einen Aufruf von WSACancelBlockingCall unterbrochen. Dieser Fehler wird zurückgegeben, wenn ein blockierende Vorgang unterbrochen wurde.
WSAEINVAL Ein ungültiges Argument wurde angegeben. Dieser Fehler wird zurückgegeben, wenn der dwIoControlCode-Parameter kein gültiger Befehl ist, ein angegebener Eingabeparameter nicht akzeptabel ist oder der Befehl nicht auf den angegebenen Sockettyp anwendbar ist.
WSAENETDOWN Bei einem Socketvorgang war das Netzwerk inaktiv. Dieser Fehler wird zurückgegeben, wenn das Netzwerksubsystem fehlgeschlagen ist.
WSAENOTSOCK Ein Vorgang wurde für etwas versucht, das kein Socket ist. Dieser Fehler wird zurückgegeben, wenn der Deskriptor s kein Socket ist.
WSAEOPNOTSUPP Der versuchte Vorgang wird für den Typ des Objekts, auf das verwiesen wird, nicht unterstützt. Dieser Fehler wird zurückgegeben, wenn der angegebene IOCTL-Befehl nicht unterstützt wird. Dieser Fehler wird auch zurückgegeben, wenn die SIO_ACQUIRE_PORT_RESERVATION IOCTL vom Transportanbieter nicht unterstützt wird. Dieser Fehler wird auch zurückgegeben, wenn versucht wird, die SIO_ACQUIRE_PORT_RESERVATION IOCTL auf einem anderen Socket als UDP oder TCP zu verwenden.

Bemerkungen

Die SIO_ACQUIRE_PORT_RESERVATION IOCTL wird unter Windows Vista und höheren Versionen des Betriebssystems unterstützt.

Anwendungen und Dienste, die Ports reservieren müssen, fallen in zwei Kategorien. Die erste Kategorie umfasst Komponenten, die einen bestimmten Port als Teil ihres Betriebs benötigen. Solche Komponenten bevorzugen es in der Regel, ihren erforderlichen Port zur Installationszeit anzugeben (z. B. in einem Anwendungsmanifest). Die zweite Kategorie umfasst Komponenten, die zur Laufzeit einen verfügbaren Port oder Portblock benötigen. Diese beiden Kategorien entsprechen spezifischen Und Wildcard-Portreservierungsanforderungen. Bestimmte Reservierungsanforderungen können persistent oder runtime sein, während Reservierungsanforderungen für Wildcardports nur zur Laufzeit unterstützt werden.

Die SIO_ACQUIRE_PORT_RESERVATION IOCTL wird verwendet, um eine Laufzeitreservierung für einen Block von TCP- oder UDP-Ports anzufordern. Für Laufzeitportreservierungen erfordert der Portpool, dass Reservierungen aus dem Prozess verwendet werden, für den die Reservierung gewährt wurde. Laufzeitportreservierungen dauern nur so lange wie die Lebensdauer des Sockets, für den die SIO_ACQUIRE_PORT_RESERVATION IOCTL aufgerufen wurde. Im Gegensatz dazu können persistente Portreservierungen, die mit der Funktion CreatePersistentTcpPortReservation oder CreatePersistentUdpPortReservation erstellt wurden, von jedem Prozess verwendet werden, der persistente Reservierungen abrufen kann.

Sobald eine TCP- oder UDP-Laufzeitportreservierung abgerufen wurde, kann eine Anwendung Portzuweisungen von der Portreservierung anfordern, indem sie einen TCP- oder UDP-Socket öffnet und dann die WSAIoctl-Funktion aufruft , die die SIO_ASSOCIATE_PORT_RESERVATION IOCTL angibt, und das Reservierungstoken übergeben, bevor sie einen Aufruf der Bindfunktion im Socket ausgibt.

Wenn sowohl die Parameter lpOverlapped als auch lpCompletionRoutineNULL sind, wird der Socket in dieser Funktion als nicht überlappender Socket behandelt. Bei einem nicht überlappenden Socket werden die Parameter lpOverlapped und lpCompletionRoutine ignoriert, mit der Ausnahme, dass die Funktion blockieren kann, wenn sich Sockets im Blockierungsmodus befinden. Wenn sich Sockets im nicht blockierenden Modus befinden, wird diese Funktion weiterhin blockiert, da diese spezielle IOCTL den nicht blockierenden Modus nicht unterstützt.

Bei überlappenden Sockets werden Vorgänge initiiert, die nicht sofort abgeschlossen werden können, und der Abschluss wird zu einem späteren Zeitpunkt angezeigt.

Jede IOCTL kann je nach Implementierung des Dienstanbieters unbegrenzt blockiert werden. Wenn die Anwendung die Blockierung in einem WSAIoctl- oder WSPIoctl-Funktionsaufruf nicht tolerieren kann, werden überlappende E/A-Vorgänge für IOCTLs empfohlen, die besonders wahrscheinlich blockiert werden.

Die SIO_ACQUIRE_PORT_RESERVATION IOCTL kann in den folgenden Fällen mit WSAEINTR oder WSA_OPERATION_ABORTED fehlschlagen:

  • Die Anforderung wird vom E/A-Manager abgebrochen.
  • Der Socket ist geschlossen.

Beispiele

Im folgenden Beispiel wird eine Laufzeitportreservierung abgerufen, dann ein Socket erstellt und ein Port aus der Laufzeitportreservierung für den Socket zugeordnet. Anschließend wird der Socket geschlossen und die Reservierung des Laufzeitports freigegeben.

#ifndef UNICODE
#define UNICODE
#endif

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <Windows.h.>
#include <winsock2.h>
#include <mstcpip.h>
#include <ws2ipdef.h>
#include <stdio.h>
#include <stdlib.h>

// Need to link with Ws2_32.lib for Winsock functions
#pragma comment(lib, "ws2_32.lib")

int wmain(int argc, WCHAR ** argv)
{

    // Declare and initialize variables

    int startPort = 0;          // host byte order
    int numPorts = 0;
    USHORT startPortns = 0;     // Network byte order

    INET_PORT_RANGE portRange = { 0 };
    INET_PORT_RESERVATION_INSTANCE portRes = { 0 };

    unsigned long status = 0;

    WSADATA wsaData = { 0 };
    int iResult = 0;

    SOCKET sock = INVALID_SOCKET;
    int iFamily = AF_INET;
    int iType = 0;
    int iProtocol = 0;

    SOCKET sockRes = INVALID_SOCKET;

    DWORD bytesReturned = 0;

    // Note that the sockaddr_in struct works only with AF_INET not AF_INET6
    // An application needs to use the sockaddr_in6 for AF_INET6
    sockaddr_in service;
    sockaddr_in sockName;
    int nameLen = sizeof (sockName);

    // Validate the parameters
    if (argc != 6) {
        wprintf
            (L"usage: %s <addressfamily> <type> <protocol> <StartingPort> <NumberOfPorts>\n",
             argv[0]);
        wprintf(L"Opens a socket for the specified family, type, & protocol\n");
        wprintf
            (L"and then acquires a runtime port reservation for the protocol specified\n");
        wprintf(L"%ws example usage\n", argv[0]);
        wprintf(L"   %ws 2 2 17 5000 20\n", argv[0]);
        wprintf(L"   where AF_INET=2 SOCK_DGRAM=2 IPPROTO_UDP=17 StartPort=5000 NumPorts=20", argv[0]);

        return 1;
    }

    iFamily = _wtoi(argv[1]);
    iType = _wtoi(argv[2]);
    iProtocol = _wtoi(argv[3]);

    startPort = _wtoi(argv[4]);
    if (startPort < 0 || startPort > 65535) {
        wprintf(L"Starting point must be either 0 or between 1 and 65,535\n");
        return 1;
    }
    startPortns = htons((USHORT) startPort);

    numPorts = _wtoi(argv[5]);
    if (numPorts < 0) {
        wprintf(L"Number of ports must be a positive number\n");
        return 1;
    }

    portRange.StartPort = startPortns;
    portRange.NumberOfPorts = (USHORT) numPorts;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wprintf(L"WSAStartup failed with error = %d\n", iResult);
        return 1;
    }

    sock = socket(iFamily, iType, iProtocol);
    if (sock == INVALID_SOCKET) {
        wprintf(L"socket function failed with error = %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    } else {
        wprintf(L"socket function succeeded\n");

        iResult =
            WSAIoctl(sock, SIO_ACQUIRE_PORT_RESERVATION, (LPVOID) & portRange,
                     sizeof (INET_PORT_RANGE), (LPVOID) & portRes,
                     sizeof (INET_PORT_RESERVATION_INSTANCE), &bytesReturned, NULL, NULL);
        if (iResult != 0) {
            wprintf(L"WSAIoctl(SIO_ACQUIRE_PORT_RESERVATION) failed with error = %d\n",
                    WSAGetLastError());
            closesocket(sock);
            WSACleanup();
            return 1;
        } else {
            wprintf
                (L"WSAIoctl(SIO_ACQUIRE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
                 bytesReturned);
            wprintf(L"  Starting port=%d,  Number of Ports=%d, Token=%I64d\n",
                    htons(portRes.Reservation.StartPort),
                    portRes.Reservation.NumberOfPorts, portRes.Token);

            sockRes = socket(iFamily, iType, iProtocol);
            if (sockRes == INVALID_SOCKET) {
                wprintf(L"socket function for second socket failed with error = %d\n",
                        WSAGetLastError());
                closesocket(sock);
                WSACleanup();
                return 1;
            } else {
                wprintf(L"socket function for second socket succeeded\n");

                iResult =
                    WSAIoctl(sock, SIO_ASSOCIATE_PORT_RESERVATION,
                             (LPVOID) & portRes.Token, sizeof (ULONG64), NULL, 0,
                             &bytesReturned, NULL, NULL);
                if (iResult != 0) {
                    wprintf
                        (L"WSAIoctl(SIO_ASSOCIATE_PORT_RESERVATION) failed with error = %d\n",
                         WSAGetLastError());
                } else {
                    wprintf
                        (L"WSAIoctl(SIO_ASSOCIATE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
                         bytesReturned);

                    service.sin_family = (ADDRESS_FAMILY) iFamily;
                    service.sin_addr.s_addr = INADDR_ANY;
                    service.sin_port = 0;

                    iResult = bind(sock, (SOCKADDR *) & service, sizeof (service));
                    if (iResult == SOCKET_ERROR)
                        wprintf(L"bind failed with error = %d\n", WSAGetLastError());
                    else {
                        wprintf(L"bind succeeded\n");
                        iResult = getsockname(sock, (SOCKADDR *) & sockName, &nameLen);
                        if (iResult == SOCKET_ERROR)
                            wprintf(L"getsockname failed with error = %d\n",
                                    WSAGetLastError());
                        else {
                            wprintf(L"getsockname succeeded\n");
                            wprintf(L"Port number allocated = %u\n",
                                    ntohs(sockName.sin_port));
                        }
                    }
                }
            }

            // comment out this block of code if you don't want to delete the reservation just created
            iResult =
                WSAIoctl(sock, SIO_RELEASE_PORT_RESERVATION, (LPVOID) & portRes.Token,
                         sizeof (ULONG64), NULL, 0, &bytesReturned, NULL, NULL);
            if (iResult != 0) {
                wprintf
                    (L"WSAIoctl(SIO_RELEASE_PORT_RESERVATION) failed with error = %d\n",
                     WSAGetLastError());
            } else {
                wprintf
                    (L"WSAIoctl(SIO_RELEASE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
                     bytesReturned);
            }
        }

        if (sockRes != INVALID_SOCKET) {
            iResult = closesocket(sockRes);
            if (iResult == SOCKET_ERROR) {
                wprintf(L"closesocket for second socket failed with error = %d\n",
                        WSAGetLastError());
            }
        }
        if (sock != INVALID_SOCKET) {
            iResult = closesocket(sock);
            if (iResult == SOCKET_ERROR) {
                wprintf(L"closesocket for first socket failed with error = %d\n",
                        WSAGetLastError());
            }
        }
    }

    WSACleanup();

    return 0;
}

Siehe auch

Akzeptieren

Binden

CreatePersistentTcpPortReservation

CreatePersistentUdpPortReservation

DeletePersistentTcpPortReservation

DeletePersistentUdpPortReservation

INET_PORT_RANGE

INET_PORT_RESERVATION_INSTANCE

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ASSOCIATE_PORT_RESERVATION

SIO_RELEASE_PORT_RESERVATION

Socket

WSAGetLastError

WSAGetOverlappedResult

WSAIoctl

WSAOVERLAPPED

WSASocketA

WSASocketW