код элемента управления SIO_ACQUIRE_PORT_RESERVATION
Описание
Код элемента управления SIO_ACQUIRE_PORT_RESERVATION получает резервирование среды выполнения для блока портов TCP или UDP.
Для выполнения этой операции вызовите функцию WSAIoctl или WSPIoctl со следующими параметрами.
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.
);
Параметры
s
Дескриптор, определяющий сокет.
dwIoControlCode
Код элемента управления для операции. Используйте SIO_ACQUIRE_PORT_RESERVATION для этой операции.
lpvInBuffer
Указатель на входной буфер. Этот параметр содержит указатель на структуру INET_PORT_RANGE , указывающую номер начальной точки и количество зарезервированных портов.
cbInBuffer
Размер входного буфера (в байтах). Этот параметр должен быть размером структуры INET_PORT_RANGE .
lpvOutBuffer
Указатель на выходной буфер. При успешном выводе этот параметр содержит указатель на структуру INET_PORT_RESERVATION_INSTANCE .
cbOutBuffer
Размер выходного буфера (в байтах). Этот параметр должен быть не ниже размера структуры INET_PORT_RESERVATION_INSTANCE .
lpcbBytesReturned
Указатель на переменную, которая получает размер данных в байтах, хранящихся в выходном буфере.
Если выходной буфер слишком мал, вызов завершается ошибкой, WSAGetLastError возвращает WSAEINVAL, а параметр lpcbBytesReturned указывает на значение DWORD , равное нулю.
Если lpOverlapped имеет значение NULL, значение DWORD , на которое указывает параметр lpcbBytesReturned , возвращаемое при успешном вызове, не может быть равным нулю.
Если параметр lpOverlapped не имеет значения NULL для перекрывающихся сокетов, операции, которые не могут быть завершены немедленно, будут инициированы, а завершение будет указано позже. Значение DWORD , на которое указывает возвращаемый параметр lpcbBytesReturned , может быть равным нулю, так как размер хранимых данных не может быть определен до завершения перекрывающейся операции. Окончательное состояние завершения можно получить, когда соответствующий метод завершения получает сигнал о завершении операции.
lpvOverlapped
Указатель на структуру WSAOVERLAPPED .
Если сокеты были созданы без перекрывающихся атрибутов, параметр lpOverlapped игнорируется.
Если объект был открыт с перекрывающимся атрибутом, а параметр lpOverlapped не имеет значения NULL, операция выполняется как перекрываемая (асинхронная) операция. В этом случае параметр lpOverlapped должен указывать на допустимую структуру WSAOVERLAPPED .
Для перекрывающихся операций функция WSAIoctl или WSPIoctl возвращается немедленно, а соответствующий метод завершения получает сигнал о завершении операции. В противном случае функция не возвращается, пока операция не будет завершена или не возникнет ошибка.
lpCompletionRoutine
Тип: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE
Указатель на подпрограмму завершения, вызываемую при завершении операции (игнорируется для неперекрывающихся сокетов).
lpThreadId
Указатель на структуру WSATHREADID , которая будет использоваться поставщиком при последующем вызове WPUQueueApc. Поставщик должен хранить указанную структуру WSATHREADID (а не указатель на нее) до тех пор, пока не будет возвращена функция WPUQueueApc .
Примечание Этот параметр применяется только к функции WSPIoctl .
lpErrno
Указатель на код ошибки.
Примечание Этот параметр применяется только к функции WSPIoctl .
Возвращаемое значение
Если операция завершается успешно, функция WSAIoctl или WSPIoctl возвращает ноль.
Если операция завершается сбоем или находится в состоянии ожидания, функция WSAIoctl или WSPIoctl возвращает SOCKET_ERROR. Чтобы получить расширенные сведения об ошибке, вызовите WSAGetLastError.
Код ошибки | Значение |
---|---|
WSA_IO_PENDING | Выполняется перекрываемая операция ввода-вывода. Это значение возвращается, если перекрываемая операция была успешно инициирована, а завершение будет указано позже. |
WSA_OPERATION_ABORTED | Операция ввода-вывода прекращена из-за выхода из потока или запроса приложения. Эта ошибка возвращается, если перекрываемая операция была отменена из-за закрытия сокета или выполнения команды IOCTL SIO_FLUSH . |
WSAEFAULT | Система обнаружила недопустимый адрес указателя при попытке использовать аргумент указателя в вызове. Эта ошибка возвращается из параметра lpvInBuffer, lpvoutBuffer, lpcbBytesReturned, lpOverlapped или lpCompletionRoutine не полностью содержится в допустимой части адресного пространства пользователя. |
WSAEINPROGRESS | В данный момент выполняется блокирующая операция. Эта ошибка возвращается, если функция вызывается при выполнении обратного вызова. |
WSAEINTR | Операция блокировки была прервана вызовом WSACancelBlockingCall. Эта ошибка возвращается, если операция блокировки была прервана. |
WSAEINVAL | Указан недопустимый аргумент. Эта ошибка возвращается, если параметр dwIoControlCode не является допустимой командой, если указанный входной параметр недопустим или команда не применима к указанному типу сокета. |
WSAENETDOWN | Операция на сокете обнаружила отключение сети. Эта ошибка возвращается в случае сбоя сетевой подсистемы. |
WSAENOTSOCK | Предпринята попытка выполнить операцию с тем, что не является сокетом. Эта ошибка возвращается, если дескриптор не является сокетом. |
WSAEOPNOTSUPP | Предпринятая операция не поддерживается для типа объекта, на который указывает ссылка. Эта ошибка возвращается, если указанная команда IOCTL не поддерживается. Эта ошибка также возвращается, если поставщик транспорта не поддерживает SIO_ACQUIRE_PORT_RESERVATION IOCTL. Эта ошибка также возвращается при попытке использовать SIO_ACQUIRE_PORT_RESERVATION IOCTL в сокете, отличном от UDP или TCP. |
Комментарии
SIO_ACQUIRE_PORT_RESERVATION IOCTL поддерживается в Windows Vista и более поздних версиях операционной системы.
Приложения и службы, которым необходимо зарезервировать порты, делятся на две категории. Первая категория включает компоненты, которым требуется определенный порт в рамках операции. Такие компоненты обычно предпочитают указывать необходимый порт во время установки (например, в манифесте приложения). Вторая категория включает компоненты, которым требуется любой доступный порт или блок портов во время выполнения. Эти две категории соответствуют конкретным запросам на резервирование портов и с подстановочными знаками. Определенные запросы на резервирование могут быть постоянными или выполняться во время выполнения, а запросы на резервирование портов с подстановочными знаками поддерживаются только во время выполнения.
SIO_ACQUIRE_PORT_RESERVATION IOCTL используется для запроса резервирования среды выполнения для блока портов TCP или UDP. Для резервирования портов среды выполнения пул портов требует, чтобы резервирования были использованы из процесса, в сокете которого было предоставлено резервирование. Резервирование портов среды выполнения выполняется только до тех пор, пока время существования сокета, в котором был вызван SIO_ACQUIRE_PORT_RESERVATION IOCTL. В отличие от этого, резервирования постоянных портов, созданные с помощью функции CreatePersistentTcpPortReservation или CreatePersistentUdpPortReservation , могут использоваться любым процессом с возможностью получения постоянных резервирований.
После получения резервирования портов TCP или UDP среды выполнения приложение может запросить назначения портов из резервирования портов, открыв сокет TCP или UDP, а затем вызвав функцию WSAIoctl , указав SIO_ASSOCIATE_PORT_RESERVATION IOCTL и передав маркер резервирования перед вызовом функции bind в сокете.
Если параметры lpOverlapped и lpCompletionRoutine имеют значение NULL, сокет в этой функции будет рассматриваться как неперекрытый сокет. Для неперекрытого сокета параметры lpOverlapped и lpCompletionRoutine игнорируются, за исключением того, что функция может блокировать, если сокет находится в режиме блокировки. Если сокет находится в неблокировочном режиме, эта функция будет по-прежнему блокироваться, так как этот конкретный IOCTL не поддерживает неблокирующий режим.
Для перекрывающихся сокетов будут инициированы операции, которые не могут быть завершены немедленно, а завершение будет указано позже.
Любой IOCTL может блокироваться на неопределенный срок в зависимости от реализации поставщика услуг. Если приложение не допускает блокировки в вызове функции WSAIoctl или WSPIoctl , для ioCTL, которые особенно вероятно, будут блокироваться перекрывающиеся операции ввода-вывода.
Сбой SIO_ACQUIRE_PORT_RESERVATION IOCTL может завершиться с помощью WSAEINTR или WSA_OPERATION_ABORTED в следующих случаях:
- Запрос отменяется диспетчером ввода-вывода.
- Сокет закрыт.
Примеры
В следующем примере выполняется получение резервирования портов среды выполнения, создание сокета и выделение порта из резервирования порта среды выполнения для сокета, а затем закрытие сокета и освобождение резервирования портов среды выполнения.
#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;
}
См. также раздел
CreatePersistentTcpPortReservation
CreatePersistentUdpPortReservation
DeletePersistentTcpPortReservation
DeletePersistentUdpPortReservation
INET_PORT_RESERVATION_INSTANCE
LookupPersistentTcpPortReservation
LookupPersistentUdpPortReservation