Compartilhar via


Função CreatePersistentTcpPortReservation (iphlpapi.h)

A função CreatePersistentTcpPortReservation cria uma reserva de porta TCP persistente para um bloco consecutivo de portas TCP no computador local.

Sintaxe

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

Parâmetros

[in] StartPort

O número da porta TCP inicial na ordem de bytes de rede.

[in] NumberOfPorts

O número de números de porta TCP a serem reservados.

[out] Token

Um ponteiro para um token de reserva de porta retornado se a função for bem-sucedida.

Retornar valor

Se a função for bem-sucedida, o valor retornado será NO_ERROR.

Se a função falhar, o valor retornado será um dos códigos de erro a seguir.

Código de retorno Descrição
ERROR_ACCESS_DENIED
Acesso negado. Esse erro é retornado sob várias condições que incluem o seguinte: o usuário não tem os privilégios administrativos necessários no computador local ou o aplicativo não está em execução em um shell aprimorado como administrador interno (administrador RunAs).
ERROR_INVALID_PARAMETER
Um parâmetro inválido foi passado para a função.

Esse erro será retornado se zero for passado nos parâmetros StartPort ou NumberOfPorts . Esse erro também será retornado se o parâmetro NumberOfPorts for muito grande, um bloco de portas, dependendo do parâmetro StartPort , de que o bloco de portas alocável excederia a porta máxima que pode ser alocada.

ERROR_SHARING_VIOLATION
O processo não pode acessar o arquivo porque ele está sendo usado por outro processo. Esse erro será retornado se uma porta TCP no bloco de portas TCP especificadas pelos parâmetros StartPort e NumberOfPorts já estiver sendo usada. Esse erro também será retornado se uma reserva persistente para um bloco de portas TCP especificado pelos parâmetros StartPort e NumberOfPorts corresponder ou sobrepor uma reserva persistente para um bloco de portas TCP que já foi criado.
Outros
Use FormatMessage para obter a cadeia de caracteres de mensagem para o erro retornado.

Comentários

A função CreatePersistentTcpPortReservation é definida no Windows Vista e posterior.

A função CreatePersistentTcpPortReservation é usada para adicionar uma reserva persistente para um bloco de portas TCP.

Aplicativos e serviços que precisam reservar portas se enquadram em duas categorias. A primeira categoria inclui componentes que precisam de uma porta específica como parte de sua operação. Esses componentes geralmente preferem especificar a porta necessária no momento da instalação (em um manifesto do aplicativo, por exemplo). A segunda categoria inclui componentes que precisam de qualquer porta disponível ou bloco de portas em runtime.

Essas duas categorias correspondem a solicitações de reserva de porta curinga e específicas. Solicitações de reserva específicas podem ser persistentes ou runtime, enquanto as solicitações de reserva de porta curinga só têm suporte no runtime.

A função CreatePersistentTcpPortReservation fornece a capacidade de um aplicativo ou serviço reservar um bloco persistente de portas TCP. As reservas de porta TCP persistentes são registradas em um repositório persistente para o módulo TCP no Windows.

Um chamador obtém uma reserva de porta persistente especificando quantas portas são necessárias e se um intervalo específico é necessário. Se a solicitação puder ser atendida, a função CreatePersistentTcpPortReservation retornará um token de ULONG64 opaco exclusivo, que identifica posteriormente a reserva. Uma reserva de porta TCP persistente pode ser liberada chamando a função DeletePersistentTcpPortReservation . Observe que o token para uma determinada reserva de porta TCP persistente pode ser alterado sempre que o sistema é reiniciado.

O Windows não implementa a segurança entre componentes para reservas persistentes obtidas usando essas funções. Isso significa que, se um componente receber a capacidade de obter reservas de porta persistentes, esse componente obterá automaticamente a capacidade de consumir quaisquer reservas de porta persistentes concedidas a qualquer outro componente no sistema. A segurança em nível de processo é imposta para reservas de runtime, mas esse controle não pode ser estendido para reservas de porta persistentes criadas usando a função CreatePersistentTcpPortReservation ou CreatePersistentUdpPortReservation .

Depois que uma reserva de porta TCP persistente tiver sido obtida, um aplicativo poderá solicitar atribuições de porta da reserva de porta TCP abrindo um soquete TCP e chamando a função WSAIoctl especificando o SIO_ASSOCIATE_PORT_RESERVATION IOCTL e passando o token de reserva antes de emitir uma chamada para a função de associação no soquete.

O SIO_ACQUIRE_PORT_RESERVATION IOCTL pode ser usado para solicitar uma reserva de runtime para um bloco de portas TCP ou UDP. Para reservas de porta de runtime, o pool de portas exige que as reservas sejam consumidas do processo em cujo soquete a reserva foi concedida. As reservas de porta de runtime duram apenas o tempo de vida do soquete no qual o SIO_ACQUIRE_PORT_RESERVATION IOCTL foi chamado. Por outro lado, as reservas de porta persistentes criadas usando a função CreatePersistentTcpPortReservation podem ser consumidas por qualquer processo com a capacidade de obter reservas persistentes.

A função CreatePersistentTcpPortReservation só pode ser chamada por um usuário conectado como membro do grupo Administradores. Se CreatePersistentTcpPortReservation for chamado por um usuário que não seja membro do grupo Administradores, a chamada de função falhará e ERROR_ACCESS_DENIED será retornado. Essa função também pode falhar devido ao UAC (controle de conta de usuário) no Windows Vista e posterior. Se um aplicativo que contém essa função for executado por um usuário conectado como um membro do grupo Administradores diferente do Administrador interno, essa chamada falhará, a menos que o aplicativo tenha sido marcado no arquivo de manifesto com um requestedExecutionLevel definido como requireAdministrator. Se o aplicativo não tiver esse arquivo de manifesto, um usuário conectado como membro do grupo Administradores diferente do Administrador interno deverá executar o aplicativo em um shell aprimorado como administrador interno (administrador RunAs) para que essa função tenha êxito.

Exemplos

O exemplo a seguir cria uma reserva de porta TCP persistente, cria um soquete e aloca uma porta da reserva de porta e fecha o soquete e exclui a reserva de porta TCP.

Este exemplo deve ser executado por um usuário que seja membro do grupo Administradores. A maneira mais simples de executar este exemplo é em um shell aprimorado como administrador interno (administrador RunAs).

#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;
}

Requisitos

Requisito Valor
Cliente mínimo com suporte Windows Vista [somente aplicativos da área de trabalho]
Servidor mínimo com suporte Windows Server 2008 [somente aplicativos da área de trabalho]
Plataforma de Destino Windows
Cabeçalho iphlpapi.h
Biblioteca Iphlpapi.lib
DLL Iphlpapi.dll

Confira também

CreatePersistentUdpPortReservation

DeletePersistentTcpPortReservation

DeletePersistentUdpPortReservation

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ACQUIRE_PORT_RESERVATION

SIO_ASSOCIATE_PORT_RESERVATION

SIO_RELEASE_PORT_RESERVATION

Wsaioctl

bind