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
CreatePersistentTcpPortReservation
CreatePersistentUdpPortReservation
DeletePersistentTcpPortReservation
DeletePersistentUdpPortReservation
INET_PORT_RESERVATION_INSTANCE
LookupPersistentTcpPortReservation
LookupPersistentUdpPortReservation