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。

如果函式失敗,傳回值就是下列其中一個錯誤碼。

傳回碼 Description
ERROR_ACCESS_DENIED
存取遭到拒絕。 此錯誤會在下列幾個情況下傳回:使用者缺少本機計算機上的必要系統管理許可權,或應用程式未在增強的殼層中執行,因為 RunAs 系統管理員) 內建系統管理員 (。
ERROR_INVALID_PARAMETER
無效的參數已傳遞至 函式。

如果在 StartPort 或 NumberOfPorts 參數中傳遞零,則會傳回此錯誤。 如果 NumberOfPorts 參數太大,視可配置埠區塊的 StartPort 參數而定,埠配置區塊超過可配置的埠上限,也會傳回此錯誤。

ERROR_SHARING_VIOLATION
由於已有另一個處理序正在使用該檔案,所以此處理序無法存取該檔案。 如果使用 StartPort 和 NumberOfPorts 參數所指定的 TCP 連接埠區塊中的 TCP 連接埠,就會傳回此錯誤。 如果 StartPort 和 NumberOfPorts 參數所指定的 TCP 埠區塊持續保留符合或重疊已建立之 TCP 連接埠區塊的持續性保留,也會傳回此錯誤。
其他
使用 FormatMessage 取得傳回錯誤的訊息字串。

備註

CreatePersistentTcpPortReservation 函式是在 Windows Vista 和更新版本上定義。

CreatePersistentTcpPortReservation 函式可用來新增 TCP 埠區塊的持續性保留。

需要保留埠的應用程式和服務分為兩種類別。 第一個類別包含需要特定埠作為其作業一部分的元件。 例如,這類元件通常會偏好在應用程式指令清單中的安裝時間 (指定其所需的埠,例如) 。 第二個類別包含元件,這些元件需要在運行時間使用任何可用的埠或埠區塊。

這兩個類別對應至特定和通配符埠保留要求。 特定保留要求可能是持續性或運行時間,而通配符埠保留要求則只在運行時間受到支援。

CreatePersistentTcpPortReservation 函式提供應用程式或服務保留持續 TCP 埠區塊的能力。 持續性 TCP 埠保留專案會記錄在 Windows 中 TCP 模組的永續性存放區中。

呼叫端藉由指定需要多少埠,以及是否需要特定範圍,來取得永續性埠保留。 如果可以滿足要求, CreatePersistentTcpPortReservation 函式會傳回唯一的不透明ULONG64令牌,其後續會識別保留。 呼叫 DeletePersistentTcpPortReservation 函式,即可釋放持續性TCP埠保留。 請注意,每次重新啟動系統時,給定持續性 TCP 埠保留的令牌可能會變更。

Windows 不會針對使用這些函式取得的持續性保留實作元件間安全性。 這表示,如果元件被授與取得任何永續性埠保留的能力,該元件會自動取得取用系統上任何其他元件所授與之任何永續性埠保留的能力。 系統會針對運行時間保留強制執行進程層級安全性,但這類控制無法延伸至使用 CreatePersistentTcpPortReservation 或 CreatePersistentUdpPortReservation 函式建立的永續性埠保留。

取得永續性 TCP 埠保留之後,應用程式可以藉由開啟 TCP 套接字來要求 TCP 連接埠保留的埠指派,然後呼叫 WSAIoctl 函式 來指定SIO_ASSOCIATE_PORT_RESERVATION IOCTL,並在對套接字上的 系結 函式發出呼叫之前傳遞保留令牌。

SIO_ACQUIRE_PORT_RESERVATION IOCTL 可用來要求 TCP 或 UDP 連接埠區塊的運行時間保留。 針對運行時間埠保留,埠集區會要求保留要取自已授與保留之套接字的進程。 只要 呼叫 SIO_ACQUIRE_PORT_RESERVATION IOCTL 的套接字存留期,運行時間埠保留才會保留。 相反地,使用 CreatePersistentTcpPortReservation 函式建立的永續性埠保留,可能會由任何能夠取得永續性保留的程式取用。

CreatePersistentTcpPortReservation 函式只能由以 Administrators 群組成員身分登入的使用者呼叫。 如果 CreatePersistentTcpPortReservation 是由不是 Administrators 群組成員的使用者呼叫,則函數調用將會失敗,並 傳回ERROR_ACCESS_DENIED 。 此函式也可能因為 Windows Vista 和更新版本的用戶帳戶控制 (UAC) 而失敗。 如果包含此函式的應用程式是由以內建系統管理員以外的 Administrators 群組成員身分登入的使用者所執行,除非應用程式已在指令清單檔案中標示 為 requestedExecutionLevel 設定為 requireAdministrator,否則此呼叫將會失敗。 如果應用程式缺少此指令清單檔,則以系統管理員以外的 Administrators 群組成員身分登入的使用者,必須在增強的殼層中執行應用程式,因為內建的 Administrator (RunAs 系統管理員) ,此函式才能成功。

範例

下列範例會建立永續性 TCP 連接埠保留,然後建立套接字,並從埠保留區配置埠,然後關閉套接字並刪除 TCP 埠保留。

此範例必須由屬於Administrators群組成員的用戶執行。 執行此範例最簡單的方式是使用增強的殼層,作為內建的 Administrator (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;
}

規格需求

需求 值
最低支援的用戶端 Windows Vista [僅限傳統型應用程式]
最低支援的伺服器 Windows Server 2008 [僅限傳統型應用程式]
目標平台 Windows
標頭 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