Función CreatePersistentTcpPortReservation (iphlpapi.h)

La función CreatePersistentTcpPortReservation crea una reserva de puertos TCP persistente para un bloque consecutivo de puertos TCP en el equipo local.

Sintaxis

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

Parámetros

[in] StartPort

Número de puerto TCP inicial en orden de bytes de red.

[in] NumberOfPorts

Número de números de puerto TCP que se van a reservar.

[out] Token

Puntero a un token de reserva de puerto que se devuelve si la función se realiza correctamente.

Valor devuelto

Si la función se realiza correctamente, el valor devuelto es NO_ERROR.

Si se produce un error en la función, el valor devuelto es uno de los siguientes códigos de error.

Código devuelto Descripción
ERROR_ACCESS_DENIED
Acceso denegado. Este error se devuelve en varias condiciones que incluyen lo siguiente: el usuario carece de los privilegios administrativos necesarios en el equipo local o la aplicación no se ejecuta en un shell mejorado como administrador integrado (administrador de RunAs).
ERROR_INVALID_PARAMETER
Se pasó un parámetro no válido a la función.

Este error se devuelve si se pasa cero en los parámetros StartPort o NumberOfPorts . Este error también se devuelve si el parámetro NumberOfPorts es demasiado grande un bloque de puertos según el parámetro StartPort que el bloque asignado de puertos superaría el puerto máximo que se puede asignar.

ERROR_SHARING_VIOLATION
El proceso no puede obtener acceso al archivo porque otro proceso lo está utilizando. Este error se devuelve si ya se está usando un puerto TCP en el bloque de puertos TCP especificado por los parámetros StartPort y NumberOfPorts . Este error también se devuelve si una reserva persistente para un bloque de puertos TCP especificado por los parámetros StartPort y NumberOfPorts coincide o se superpone a una reserva persistente para un bloque de puertos TCP que ya se creó.
Otros
Use FormatMessage para obtener la cadena de mensaje del error devuelto.

Comentarios

La función CreatePersistentTcpPortReservation se define en Windows Vista y versiones posteriores.

La función CreatePersistentTcpPortReservation se usa para agregar una reserva persistente para un bloque de puertos TCP.

Las aplicaciones y los servicios que necesitan reservar puertos se dividen en dos categorías. La primera categoría incluye componentes que necesitan un puerto determinado como parte de su operación. Por lo general, estos componentes prefieren especificar su puerto necesario en el momento de la instalación (por ejemplo, en un manifiesto de aplicación). La segunda categoría incluye componentes que necesitan cualquier puerto o bloque de puertos disponibles en tiempo de ejecución.

Estas dos categorías corresponden a solicitudes de reserva de puertos comodín y específicas. Las solicitudes de reserva específicas pueden ser persistentes o en tiempo de ejecución, mientras que las solicitudes de reserva de puerto comodín solo se admiten en tiempo de ejecución.

La función CreatePersistentTcpPortReservation proporciona la posibilidad de que una aplicación o servicio reserve un bloque persistente de puertos TCP. Las reservas de puertos TCP persistentes se registran en un almacén persistente para el módulo TCP en Windows.

Un llamador obtiene una reserva de puerto persistente especificando cuántos puertos son necesarios y si se necesita un intervalo específico. Si se puede satisfacer la solicitud, la función CreatePersistentTcpPortReservation devuelve un token de ULONG64 opaco único, que posteriormente identifica la reserva. Se puede liberar una reserva de puertos TCP persistente llamando a la función DeletePersistentTcpPortReservation . Tenga en cuenta que el token de una reserva de puerto TCP persistente determinada puede cambiar cada vez que se reinicia el sistema.

Windows no implementa la seguridad entre componentes para las reservas persistentes obtenidas mediante estas funciones. Esto significa que, si se concede a un componente la capacidad de obtener reservas de puertos persistentes, ese componente obtiene automáticamente la capacidad de consumir cualquier reserva de puerto persistente concedida a cualquier otro componente del sistema. La seguridad de nivel de proceso se aplica para las reservas en tiempo de ejecución, pero este control no se puede extender a las reservas de puertos persistentes creadas mediante la función CreatePersistentTcpPortReservation o CreatePersistentUdpPortReservation .

Una vez que se ha obtenido una reserva de puertos TCP persistente, una aplicación puede solicitar asignaciones de puertos de la reserva de puertos TCP abriendo un socket TCP y llamando a la función WSAIoctl especificando el IOCTL de SIO_ASSOCIATE_PORT_RESERVATION y pasando el token de reserva antes de emitir una llamada a la función de enlace en el socket.

El SIO_ACQUIRE_PORT_RESERVATION IOCTL se puede usar para solicitar una reserva en tiempo de ejecución para un bloque de puertos TCP o UDP. Para las reservas de puertos en tiempo de ejecución, el grupo de puertos requiere que las reservas se consuman desde el proceso en cuyo socket se concedió la reserva. Las reservas de puertos en tiempo de ejecución solo duran mientras dure el socket en el que se llamó al SIO_ACQUIRE_PORT_RESERVATION IOCTL. En cambio, las reservas de puertos persistentes creadas mediante la función CreatePersistentTcpPortReservation pueden consumirse en cualquier proceso con la capacidad de obtener reservas persistentes.

Un usuario que inició sesión como miembro del grupo Administradores solo puede llamar a la función CreatePersistentTcpPortReservation . Si un usuario llama a CreatePersistentTcpPortReservation que no es miembro del grupo Administradores, se producirá un error en la llamada a la función y se devolverá ERROR_ACCESS_DENIED . Esta función también puede producir un error debido al control de cuentas de usuario (UAC) en Windows Vista y versiones posteriores. Si un usuario inicia sesión como miembro del grupo Administradores que no sea el administrador integrado, esta llamada producirá un error a menos que la aplicación se haya marcado en el archivo de manifiesto con un valor requestedExecutionLevel establecido en requireAdministrator. Si la aplicación carece de este archivo de manifiesto, un usuario que inició sesión como miembro del grupo Administradores que no sea el administrador integrado debe ejecutar la aplicación en un shell mejorado como administrador integrado (administrador de RunAs) para que esta función se realice correctamente.

Ejemplos

En el ejemplo siguiente se crea una reserva de puertos TCP persistente y, a continuación, se crea un socket y se asigna un puerto de la reserva de puertos y, a continuación, se cierra el socket y se elimina la reserva de puerto TCP.

Este ejemplo debe ejecutarse por un usuario que sea miembro del grupo Administradores. La manera más sencilla de ejecutar este ejemplo es en un shell mejorado como administrador integrado (administrador de 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 Value
Cliente mínimo compatible Windows Vista [solo aplicaciones de escritorio]
Servidor mínimo compatible Windows Server 2008 [solo aplicaciones de escritorio]
Plataforma de destino Windows
Encabezado iphlpapi.h
Library Iphlpapi.lib
Archivo DLL Iphlpapi.dll

Consulte también

CreatePersistentUdpPortReservation

DeletePersistentTcpPortReservation

DeletePersistentUdpPortReservation

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ACQUIRE_PORT_RESERVATION

SIO_ASSOCIATE_PORT_RESERVATION

SIO_RELEASE_PORT_RESERVATION

WSAIoctl

bind