Поделиться через


код элемента управления 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_RANGE

INET_PORT_RESERVATION_INSTANCE

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ASSOCIATE_PORT_RESERVATION

SIO_RELEASE_PORT_RESERVATION

Сокета

WSAGetLastError

WSAGetOverlappedResult

WSAIoctl

WSAOVERLAPPED

WSASocketA

WSASocketW