Функция CreatePersistentTcpPortReservation (iphlpapi.h)

Функция CreatePersistentTcpPortReservation создает постоянное резервирование TCP-портов для последовательного блока TCP-портов на локальном компьютере.

Синтаксис

IPHLPAPI_DLL_LINKAGE ULONG CreatePersistentTcpPortReservation(
  [in]  USHORT   StartPort,
  [in]  USHORT   NumberOfPorts,
  [out] PULONG64 Token
);

Параметры

[in] StartPort

Начальный номер TCP-порта в сетевом порядке байтов.

[in] NumberOfPorts

Число зарезервированных номеров TCP-портов.

[out] Token

Указатель на маркер резервирования портов, который возвращается при успешном выполнении функции.

Возвращаемое значение

Если функция выполнена успешно, возвращаемое значение будет NO_ERROR.

Если функция завершается сбоем, возвращается один из следующих кодов ошибок.

Код возврата Описание
ERROR_ACCESS_DENIED
Отказано в доступе". Эта ошибка возвращается при нескольких условиях, которые включают следующее: у пользователя отсутствуют необходимые права администратора на локальном компьютере или приложение не работает в расширенной оболочке в качестве встроенного администратора (администратор запуска от имени администратора).
ERROR_INVALID_PARAMETER
В функцию передан недопустимый параметр.

Эта ошибка возвращается, если в параметрах StartPort или NumberOfPorts передается ноль. Эта ошибка также возвращается, если параметр NumberOfPorts слишком велик на блок портов в зависимости от параметра StartPort , что выделенный блок портов превысит максимальное количество портов, которое может быть выделено.

ERROR_SHARING_VIOLATION
The process cannot access the file because it is being used by another process. Эта ошибка возвращается, если TCP-порт в блоке TCP-портов, указанных параметрами StartPort и NumberOfPorts , уже используется. Эта ошибка также возвращается, если постоянное резервирование для блока TCP-портов, указанных параметрами StartPort и NumberOfPorts , совпадает или перекрывает постоянное резервирование для уже созданного блока TCP-портов.
Другое
Используйте FormatMessage , чтобы получить строку сообщения для возвращаемой ошибки.

Комментарии

Функция CreatePersistentTcpPortReservation определена в Windows Vista и более поздних версиях.

Функция CreatePersistentTcpPortReservation используется для добавления постоянного резервирования для блока TCP-портов.

Приложения и службы, которым необходимо зарезервировать порты, делятся на две категории. Первая категория включает компоненты, которым требуется определенный порт в рамках операции. Такие компоненты обычно предпочитают указывать необходимый порт во время установки (например, в манифесте приложения). Вторая категория включает компоненты, которым требуется любой доступный порт или блок портов во время выполнения.

Эти две категории соответствуют конкретным запросам на резервирование портов и с подстановочными знаками. Определенные запросы на резервирование могут быть постоянными или выполняться во время выполнения, а запросы на резервирование портов с подстановочными знаками поддерживаются только во время выполнения.

Функция CreatePersistentTcpPortReservation позволяет приложению или службе резервировать постоянный блок TCP-портов. Постоянные резервирования TCP-портов записываются в постоянное хранилище для модуля TCP в Windows.

Вызывающий объект получает постоянное резервирование портов, указывая, сколько портов требуется и требуется ли определенный диапазон. Если запрос может быть удовлетворен, функция CreatePersistentTcpPortReservation возвращает уникальный непрозрачный маркер ULONG64, который впоследствии идентифицирует резервирование. Постоянное резервирование TCP-портов можно освободить, вызвав функцию DeletePersistentTcpPortReservation . Обратите внимание, что маркер для заданного постоянного резервирования TCP-порта может изменяться при каждом перезапуске системы.

Windows не реализует межкомпонентную безопасность для постоянных резервирований, полученных с помощью этих функций. Это означает, что если компоненту предоставляется возможность получать постоянные резервирования портов, этот компонент автоматически получает возможность использовать все постоянные резервирования портов, предоставленные любому другому компоненту в системе. Безопасность на уровне процесса применяется для резервирований среды выполнения, но такое управление не может быть расширено на постоянные резервирования портов, созданные с помощью функции CreatePersistentTcpPortReservation или CreatePersistentUdpPortReservation .

После получения постоянного резервирования TCP-порта приложение может запросить назначения портов из резервирования TCP-портов, открыв сокет TCP, а затем вызвав функцию WSAIoctl , указав SIO_ASSOCIATE_PORT_RESERVATION IOCTL и передав маркер резервирования перед вызовом функции bind в сокете.

SIO_ACQUIRE_PORT_RESERVATION IOCTL можно использовать для запроса резервирования среды выполнения для блока портов TCP или UDP. Для резервирования портов среды выполнения пул портов требует, чтобы резервирования были использованы из процесса, в сокете которого было предоставлено резервирование. Резервирование портов среды выполнения выполняется только до тех пор, пока время существования сокета, в котором был вызван SIO_ACQUIRE_PORT_RESERVATION IOCTL. В отличие от этого, резервирования постоянных портов, созданные с помощью функции CreatePersistentTcpPortReservation , могут использоваться любым процессом с возможностью получения постоянных резервирований.

Функция CreatePersistentTcpPortReservation может вызываться только пользователем, вошедшего в систему как член группы администраторов. Если метод CreatePersistentTcpPortReservation вызывается пользователем, не включаемым в группу Администраторы, вызов функции завершится ошибкой и возвращается ERROR_ACCESS_DENIED . Эта функция также может завершиться сбоем из-за контроля учетных записей (UAC) в Windows Vista и более поздних версиях. Если приложение, содержащее эту функцию, выполняется пользователем, вошедшего в систему как член группы администраторов, отличный от встроенного администратора, этот вызов завершится ошибкой, если приложение не было отмечено в файле манифеста с параметром requestedExecutionLevel , для которого задано значение requireAdministrator. Если в приложении отсутствует этот файл манифеста, пользователь, вошедший в систему как член группы администраторов, отличный от встроенного администратора, должен выполнить приложение в расширенной оболочке в качестве встроенного администратора (администратора запуска от имени), чтобы эта функция была успешной.

Примеры

В следующем примере создается постоянное резервирование TCP-портов, затем создается сокет и выделяется порт из резервирования портов, а затем закрывается сокет и удаляется резервирование TCP-порта.

Этот пример должен выполнять пользователь, который является членом группы "Администраторы". Самый простой способ запустить этот пример — в расширенной оболочке в качестве встроенного администратора (администратор запуска от имени).

#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 <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>

// Need to link with iphlpapi.lib
#pragma comment(lib, "iphlpapi.lib")

// 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
    ULONG64 resToken = { 0 };

    unsigned long status = 0;

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

    SOCKET sock = INVALID_SOCKET;
    int iFamily = AF_INET;
    int iType = SOCK_STREAM;
    int iProtocol = IPPROTO_TCP;

    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 != 3) {
        wprintf(L"usage: %s <Starting Port> <Number of Ports>\n",
             argv[0]);
        wprintf(L"Creates a persistent TCP port reservation\n");
        wprintf(L"Example usage:\n");
        wprintf(L"   %s 5000 20\n", argv[0]);
        wprintf(L"   where StartPort=5000 NumPorts=20");
        return 1;
    }

    startPort = _wtoi(argv[1]);
    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[2]);
    if (numPorts < 0) {
        wprintf(L"Number of ports must be a positive number\n");
        return 1;
    }

    status =
        CreatePersistentTcpPortReservation((USHORT) startPortns, (USHORT) numPorts,
                                           &resToken);
    if (status != NO_ERROR) {
        wprintf(L"CreatePersistentTcpPortReservation returned error: %ld\n", status);
        return 1;
    }

    wprintf(L"CreatePersistentTcpPortReservation call succeeded\n");
    wprintf(L"  Token = %I64d\n", resToken);

    // Comment out this block if you don't want to create a socket and associate it with the 
    // persistent reservation

    // 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());
    else {
        wprintf(L"socket function succeeded\n");

        iResult =
            WSAIoctl(sock, SIO_ASSOCIATE_PORT_RESERVATION, (LPVOID) & resToken,
                     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 = AF_INET;
            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) );
                }
            }                  
        }

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

    // comment out this block of code if you don't want to delete the reservation just created
    status = DeletePersistentTcpPortReservation((USHORT) startPortns, (USHORT) numPorts);
    if (status != NO_ERROR) {
        wprintf(L"DeletePersistentTcpPortReservation returned error: %ld\n", status);
        return 1;
    }
    wprintf(L"DeletePersistentTcpPortReservation call succeeded\n");

    return 0;
}

Требования

Требование Значение
Минимальная версия клиента Windows Vista [только классические приложения]
Минимальная версия сервера Windows Server 2008 [только классические приложения]
Целевая платформа Windows
Header iphlpapi.h
Библиотека Iphlpapi.lib
DLL Iphlpapi.dll

См. также раздел

CreatePersistentUdpPortReservation

DeletePersistentTcpPortReservation

DeletePersistentUdpPortReservation

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ACQUIRE_PORT_RESERVATION

SIO_ASSOCIATE_PORT_RESERVATION

SIO_RELEASE_PORT_RESERVATION

WSAIoctl

bind