SIO_RELEASE_PORT_RESERVATION控制代码

说明

SIO_RELEASE_PORT_RESERVATION控制代码为 TCP 或 UDP 端口块释放运行时预留。 必须已使用 IOCTL SIO_ACQUIRE_PORT_RESERVATION 从颁发进程获取要释放的运行时预留。

若要执行此操作,请使用以下参数调用 WSAIoctlWSPIoctl 函数。

int WSAIoctl(
  (socket) s,             // descriptor identifying a socket
  SIO_RELEASE_PORT_RESERVATION, // dwIoControlCode
  (LPVOID) lpvInBuffer,  // pointer to a INET_PORT_RESERVATION_TOKEN structure
  (DWORD) cbInBuffer,    // size, in bytes, of the input buffer
  NULL,           // lpvOutBuffer is a pointer to the output buffer
  0,              // cbOutBuffer is the 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_RELEASE_PORT_RESERVATION, // dwIoControlCode
  (LPVOID) lpvInBuffer,  // pointer to a INET_PORT_RESERVATION_TOKEN structure
  (DWORD) cbInBuffer,    // size, in bytes, of the input buffer
  NULL,           // lpvOutBuffer is a pointer to the output buffer
  0,              // cbOutBuffer is the 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.
);

parameters

S

标识套接字的描述符。

dwIoControlCode

操作的控制代码。 对此操作使用 SIO_RELEASE_PORT_RESERVATION

lpvInBuffer

指向输入缓冲区的指针。 此参数包含指向 INET_PORT_RESERVATION_TOKEN 结构的指针,其中包含要发布的 TCP 或 UDP 端口预留的令牌。

cbInBuffer

输入缓冲区的大小(以字节为单位)。 此参数必须至少为 INET_PORT_RESERVATION_TOKEN 结构的大小。

lpvOutBuffer

指向输出缓冲区的指针。 此参数未用于此操作。

cbOutBuffer

输出缓冲区的大小(以字节为单位)。 该参数必须设置为零。

lpcbBytesReturned

指向变量的指针,该变量接收存储在输出缓冲区中的数据的大小(以字节为单位)。

如果输出缓冲区太小,则调用失败, WSAGetLastError 返回 WSAEINVALlBytesReturned 参数指向 DWORD 值零。

如果 lpOverlappedNULL,则成功调用时返回的 lpcbBytesReturned 参数指向的 DWORD 值不能为零。

如果对于重叠套接字, lpOverlapped 参数不是 NULL ,则将启动无法立即完成的操作,并在以后的时间指示完成。 返回的 lpcbBytesReturned 参数指向的 DWORD 值可能为零,因为在重叠操作完成之前无法确定存储的数据的大小。 当操作完成时发出相应的完成方法信号时,可以检索最终完成状态。

lpvOverlapped

指向 WSAOVERLAPPED 结构的指针。

如果套接字 是在 不使用重叠属性的情况下创建的,则忽略 lpOverlapped 参数。

如果 使用重叠属性打开,并且 lpOverlapped 参数不是 NULL,则该操作将作为重叠 (异步) 操作执行。 在这种情况下, lpOverlapped 参数必须指向有效的 WSAOVERLAPPED 结构。

对于重叠操作, WSAIoctlWSPIoctl 函数将立即返回,并在操作完成时发出相应的完成方法的信号。 否则,函数在操作完成或发生错误之前不会返回。

lpCompletionRoutine

类型:_In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

指向完成操作时调用的完成例程的指针, (忽略非重叠套接字) 。

lpThreadId

指向 WSATHREADID 结构的指针,供提供程序在后续调用 WPUQueueApc 时使用。 在 WPUQueueApc 函数返回之前,提供程序应存储引用的 WSATHREADID 结构 (而不是指向同一) 的指针。

注意 此参数仅适用于 WSPIoctl 函数。

lpErrno

指向错误代码的指针。

注意 此参数仅适用于 WSPIoctl 函数。

返回值

如果操作成功完成, WSAIoctlWSPIoctl 函数将返回零。

如果操作失败或挂起, WSAIoctlWSPIoctl 函数将返回 SOCKET_ERROR。 若要获取扩展错误信息,请调用 WSAGetLastError

错误代码 含义
WSA_IO_PENDING 重叠的 I/O 操作正在进行中。 如果已成功启动重叠操作,并且稍后将指示完成,则返回此值。
WSA_OPERATION_ABORTED 由于发生线程退出或应用程序请求,I/O 操作已中止。 如果由于套接字关闭或执行 SIO_FLUSH IOCTL 命令而取消了重叠操作,则返回此错误。
WSAEFAULT 系统在尝试在调用中使用指针参数时检测到指针地址无效。 此错误返回 lpOverlappedlpCompletionRoutine 参数未完全包含在用户地址空间的有效部分。
WSAEINPROGRESS 阻止操作当前正在执行。 如果在回调正在进行时调用函数,则返回此错误。
WSAEINTR 调用 WSACancelBlockingCall 中断了阻止操作。 如果阻止操作中断,则返回此错误。
WSAEINVAL 提供了无效的参数。 如果 dwIoControlCode 参数不是有效的命令,或者指定的输入参数不可接受,或者命令不适用于指定的套接字类型,则返回此错误。
WSAENETDOWN 套接字操作遇到了一个已死的网络。 如果网络子系统发生故障,则返回此错误。
WSAENOTSOCK 尝试对不是套接字的内容执行操作。 如果描述符 不是 套接字,则返回此错误。
WSAEOPNOTSUPP 引用的对象类型不支持尝试的操作。 如果不支持指定的 IOCTL 命令,则返回此错误。 如果传输提供程序不支持 SIO_RELEASE_PORT_RESERVATION IOCTL,也会返回此错误。 在 UDP 或 TCP 以外的套接字上尝试使用 IOCTL SIO_RELEASE_PORT_RESERVATION 时,也会返回此错误。

备注

SIO_RELEASE_PORT_RESERVATION IOCTL 在 Windows Vista 和更高版本的操作系统上受支持。

需要保留端口的应用程序和服务分为两类。 第一个类别包括需要特定端口作为其操作的一部分的组件。 此类组件通常更倾向于在应用程序清单中 (在安装时指定所需的端口,例如) 。 第二类包括运行时需要任何可用端口或端口块的组件。 这两个类别对应于特定和通配符端口预留请求。 特定的预留请求可能是永久性的,也可以是运行时,而通配符端口预留请求仅在运行时受支持。

SIO_ACQUIRE_PORT_RESERVATION IOCTL 用于请求 TCP 或 UDP 端口块的运行时预留。 对于运行时端口预留,端口池要求从向其授予预留的套接字的进程使用预留。 运行时端口预留仅持续到调用 SIO_ACQUIRE_PORT_RESERVATION IOCTL 的套接字的生存期。 相比之下,使用 CreatePersistentTcpPortReservationCreatePersistentUdpPortReservation 函数创建的永久性端口预留可由任何能够获取持久预留的进程使用。

SIO_RELEASE_PORT_RESERVATION IOCTL 用于释放 TCP 或 UDP 端口块的运行时预留。

如果 lpOverlappedlpCompletionRoutine 参数均为 NULL,则此函数中的套接字将被视为非重叠套接字。 对于非重叠套接字, 将忽略 lpOverlappedlpCompletionRoutine 参数,但 如果套接字 处于 阻止模式,函数可以阻止。 如果 套接字 处于 非阻塞模式,则此函数仍将阻止,因为此特定 IOCTL 不支持非阻塞模式。

对于重叠的套接字,将启动无法立即完成的操作,并在以后指示完成。

任何 IOCTL 都可能无限期阻止,具体取决于服务提供商的实现。 如果应用程序不能容忍 WSAIoctlWSPIoctl 函数调用中的阻塞,则会建议对特别可能阻止的 IOCTL 使用重叠 I/O。

在以下情况下 ,SIO_RELEASE_PORT_RESERVATION 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;

    // 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);

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

另请参阅

CreatePersistentTcpPortReservation

CreatePersistentUdpPortReservation

DeletePersistentTcpPortReservation

DeletePersistentUdpPortReservation

INET_PORT_RESERVATION_TOKEN

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ACQUIRE_PORT_RESERVATION

SIO_ASSOCIATE_PORT_RESERVATION

socket

WSAGetLastError

WSAGetOverlappedResult

WSAIoctl

WSAOVERLAPPED

WSASocketA

WSASocketW