SIO_ACQUIRE_PORT_RESER加值稅ION控制項程式碼

描述

SIO_ACQUIRE_PORT_RESER加值稅ION控制程式代碼會取得 TCP 或 UDP 埠區塊的執行時間保留。

若要執行這項作業,請使用下列參數呼叫 WSAIoctlWSPIoctl 函 式。

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_RESER加值稅ION

lpvInBuffer

輸入緩衝區的指標。 此參數包含 INET_PORT_RANGE 結構的指標,指定要保留的起始點編號和埠數目。

cbInBuffer

輸入緩衝區的大小,以位元組為單位。 此參數應該是 INET_PORT_RANGE 結構的大小。

lpvOutBuffer

輸出緩衝區的指標。 在成功的輸出上,此參數包含 INET_PORT_RESER加值稅ION_INSTANCE 結構的指標。

cbOutBuffer

輸出緩衝區的大小,以位元組為單位。 這個參數至少必須是 INET_PORT_RESER加值稅ION_INSTANCE 結構的大小。

lmicrosoftBytesReturned

變數的指標,接收儲存在輸出緩衝區中的資料大小,以位元組為單位。

如果輸出緩衝區太小,則呼叫會失敗, WSAGetLastError 會傳回 WSAEINVAL,而 lBytesReturned 參數會指向 零的 DWORD 值。

如果lpOverlappedNull,則成功呼叫時所傳回之lBytesReturned參數所指向的DWORD值不能為零。

如果重迭通訊端的 lpOverlapped 參數不是 Null ,則無法立即完成的作業將會起始,且稍後會指出完成。 由傳回之lBytesReturned參數所指向的DWORD值可能是零,因為儲存的資料大小在重迭作業完成之前無法判斷。 當作業完成完成時,可以擷取適當的完成方法時,擷取最終完成狀態。

lpvOverlapped

WSAOVERLAPPED結構的指標。

如果 建立的 通訊端沒有重迭屬性,則會忽略 lpOverlapped 參數。

如果 已使用重迭屬性開啟 lpOverlapped 參數不是 Null,則會以重迭 (非同步) 作業來執行作業。 在此情況下, lpOverlapped 參數必須指向有效的 WSAOVERLAPPED 結構。

對於重迭的作業, WSAIoctlWSPIoctl 函式會立即傳回,並在作業完成時發出適當的完成方法訊號。 否則,函式不會在作業完成或發生錯誤之前傳回。

lpCompletionRoutine

類型:_In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

當作業完成時呼叫的完成常式指標, (忽略非重迭通訊端) 。

lpThreadId

提供者後續呼叫WPUQueueApc時要使用的WSATHREADID結構的指標。 提供者應該儲存參考的 WSATHREADID 結構, (直到 WPUQueueApc 函式傳回之後,才儲存相同) 的指標。

注意 此參數僅適用于 WSPIoctl 函 式。

lpErrno

錯誤碼的指標。

注意 此參數僅適用于 WSPIoctl 函 式。

傳回值

如果作業順利完成, WSAIoctlWSPIoctl 函式會傳回零。

如果作業失敗或擱置中, WSAIoctlWSPIoctl 函式會 傳回SOCKET_ERROR。 若要取得擴充的錯誤資訊,請呼叫 WSAGetLastError

錯誤碼 意義
WSA_IO_PENDING 重迭的 I/O 作業正在進行中。 如果成功起始重迭的作業,且稍後將會指出完成,則會傳回此值。
WSA_OPERATION_ABORTED 由於執行緒結束或應用程式的要求,因此已經中止 I/O 作業。 如果因為通訊端關閉或 執行 SIO_FLUSH IOCTL 命令而取消重迭的作業,就會傳回此錯誤。
WSAEFAULT 系統在嘗試在呼叫中使用指標引數時偵測到不正確指標位址。 這個錯誤會傳回 lpvInBufferlpvoutBufferlBytesReturnedlpOverlappedlpCompletionRoutine 參數,完全不包含在使用者位址空間的有效部分中。
WSAEINPROGRESS 正在執行封鎖作業。 如果在回呼進行中時叫用函式,就會傳回此錯誤。
WSAEINTR 封鎖作業因 呼叫 WSACancelBlockingCall而中斷。 如果封鎖作業中斷,就會傳回此錯誤。
WSAEINVAL 提供的引數無效。 如果 dwIoControlCode 參數不是有效的命令,或無法接受指定的輸入參數,或命令不適用於指定的通訊端類型,就會傳回此錯誤。
WSAENETDOWN 通訊端作業遇到停止的網路。 如果網路子系統失敗,就會傳回此錯誤。
WSAENOTSOCK 嘗試在不是通訊端的內容上執行作業。 如果描述元 s 不是通訊端,則會傳回此錯誤。
WSAEOPNOTSUPP 所參考物件的類型不支援嘗試的作業。 如果不支援指定的 IOCTL 命令,則會傳回此錯誤。 如果傳輸提供者不支援 SIO_ACQUIRE_PORT_RESER加值稅ION IOCTL,也會傳回此錯誤。 嘗試在 UDP 或 TCP 以外的通訊端上 SIO_ACQUIRE_PORT_RESER加值稅ION IOCTL 時,也會傳回此錯誤。

備註

Windows Vista 和更新版本的作業系統支援 SIO_ACQUIRE_PORT_RESER加值稅ION IOCTL。

需要保留埠的應用程式和服務分為兩種類別。 第一個類別包含需要特定埠作為其作業一部分的元件。 例如,這類元件通常會偏好在應用程式資訊清單中的安裝時間 (指定其所需的埠,例如) 。 第二個類別包含元件,這些元件需要在執行時間使用任何可用的埠或埠區塊。 這兩個類別對應至特定和萬用字元埠保留要求。 特定保留要求可能是持續性或執行時間,而萬用字元埠保留要求則只在執行時間受到支援。

SIO_ACQUIRE_PORT_RESER加值稅ION IOCTL 可用來要求 TCP 或 UDP 埠區塊的運行 時間 保留。 針對執行時間埠保留,埠集區會要求保留要取自已授與保留之通訊端的進程。 只要 呼叫 SIO_ACQUIRE_PORT_RESER加值稅ION IOCTL 的通訊端存留期,執行時間埠保留才會保留。 相反地,使用 CreatePersistentTcpPortReservationCreatePersistentUdpPortReservation 函式建立的永續性埠保留,可由任何能夠取得持續性保留的程式取用。

取得執行時間 TCP 或 UDP 埠保留之後,應用程式可以藉由開啟 TCP 或 UDP 通訊端來要求埠保留的埠指派,然後呼叫 WSAIoctl 函式來指定 SIO_ASSOCIATE_PORT_RESER加值稅ION IOCTL,並在對通訊端上的系結函式發出呼叫之前傳遞保留權杖。

如果 lpOverlappedlpCompletionRoutine 參數都是 Null,此函式中的通訊端將會被視為非重迭的通訊端。 若為非重迭的通訊端,則會忽略 lpOverlappedlpCompletionRoutine 參數,不同之處在于,如果通訊端 s 處於封鎖模式,函式可以封鎖。 如果 通訊端處於 非封鎖模式,此函式仍會封鎖,因為這個特定的 IOCTL 不支援非封鎖模式。

對於重迭的通訊端,無法立即完成的作業將會起始,而且稍後會指出完成。

根據服務提供者的實作而定,任何 IOCTL 可能會無限期地封鎖。 如果應用程式無法容忍 WSAIoctl 或 WSPIoctl 函式呼叫中的封鎖,則特別可能封鎖的 IOCTL 建議重迭的 I/O。

SIO_ACQUIRE_PORT_RESER加值稅ION IOCTL 在下列情況下,WSAEINTRWSA_OPERATION_ABORTED可能會失敗:

  • I/O 管理員會取消要求。
  • 通訊端已關閉。

範例

下列範例會取得執行時間埠保留,然後建立通訊端,並從通訊端的執行時間埠保留區配置埠,然後關閉通訊端並釋放執行時間埠保留。

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

另請參閱

接受

bind

CreatePersistentTcpPortReservation

CreatePersistentUdpPortReservation

DeletePersistentTcpPortReservation

DeletePersistentUdpPortReservation

INET_PORT_RANGE

INET_PORT_RESER加值稅ION_INSTANCE

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ASSOCIATE_PORT_RESER加值稅ION

SIO_RELEASE_PORT_RESER加值稅ION

socket

WSAGetLastError

WSAGetOverlappedResult

WSAIoctl

WSAOVERLAPPED

WSASocketA

WSASocketW