WSPStartup 函数 (ws2spi.h)

WSPStartup 函数启动使用 Windows 套接字服务提供程序接口, (客户端) SPI。

语法

int WSPStartup(
  [in]  WORD                wVersionRequested,
  [out] LPWSPDATA           lpWSPData,
  [in]  LPWSAPROTOCOL_INFOW lpProtocolInfo,
  [in]  WSPUPCALLTABLE      UpcallTable,
  [out] LPWSPPROC_TABLE     lpProcTable
);

参数

[in] wVersionRequested

调用方可以使用的最高版本的 Windows 套接字 SPI 支持。 高位字节指定次要版本 (修订版) 编号;低位字节指定主版本号。

[out] lpWSPData

指向 WSPDATA 数据结构的指针,该结构接收有关 Windows 套接字服务提供程序的信息。

[in] lpProtocolInfo

指向 WSAProtocol_Info 结构的指针,该结构定义所需协议的特征。 当单个提供程序 DLL 能够实例化多个不同的服务提供程序时,这尤其有用。

[in] UpcallTable

Winsock 2 DLL (Ws2_32.dll) 在 WSPUpCallTable 结构中传递的httpall调度表。

[out] lpProcTable

指向 SPI 函数指针表的指针。 此表作为 WSPProc_Table 结构返回。

返回值

如果成功, 则 WSPStartup 函数返回零。 否则,它将返回下面列出的错误代码之一。

错误代码 含义
WSASYSNOTREADY
网络子系统不可用。 如果 Windows 套接字实现目前无法正常工作,则返回此错误,因为它用于提供网络服务的基础系统当前不可用。
WSAVERNOTSUPPORTED
Winsock.dll 版本在范围外。 如果此特定 Windows 套接字服务提供程序未提供所请求的 Windows 套接字 SPI 支持版本,则返回此错误。
WSAEINPROGRESS
阻止 Windows 套接字 1.1 操作正在进行。
WSAEPROCLIM
已达到 Windows 套接字实现支持的任务数限制。
WSAEFAULT
lpWSPDatalpProcTable 参数无效。

注解

Windows 套接字 2 传输服务提供程序是具有单个导出过程入口点 WSPStartup 的 DLL,用于服务提供程序初始化函数。 Winsock 2 DLL 可通过在 lpProcTable 参数中传递给 WSPStartup 函数的服务提供商调度表访问所有其他服务提供程序函数。 仅当需要时,WinSock 2 DLL 才会将服务提供程序 DLL 加载到内存中,并在不再需要其服务时卸载。

服务提供程序接口还定义了传输服务提供程序调用 Winsock 2 DLL () 以获取 DLL 支持服务的几种情况。 传输服务提供程序在传递给 WSPStartup 函数的HttpallTable 参数中返回 Winsock 2 DLL 的httpall 调度表。

WSPStartup 函数必须是 Windows 套接字 SPI 客户端基于每个进程调用的第一个 Windows 套接字 SPI 函数。 它允许客户端指定所需的 Windows 套接字 SPI 版本,并提供其httpall调度表。 所有 (即,Windows 套接字服务提供程序创建的以 WPU) 为前缀的函数都通过客户端的httpall调度表调用。 此函数还允许客户端检索特定 Windows 套接字服务提供程序实现的详细信息。 Windows 套接字 SPI 客户端只能在成功调用 WSPStartup 后发出进一步的 Windows 套接字 SPI 函数。 通过返回 WSPProc_Table 结构的 lpProcTable 参数检索指向其余 SPI 函数 指针表。

Winsock 2 DLL 使用标准 Windows 动态库加载机制将服务提供程序的接口 DLL 加载到系统中,并通过调用 WSPStartup 函数对其进行初始化。 这通常由调用 套接字WSASocket 函数的应用程序触发,以便创建与接口 DLL 当前未加载到内存中的服务提供程序关联的新套接字。

为了支持未来版本的 Windows 套接字 SPI 和 Ws2_32.dll(它们可能与当前 Windows 套接字 SPI 具有功能差异),在 WSPStartup 中进行了协商。 WSPStartup 的调用方 (Ws2_32.dll 或分层协议) 和 Windows 套接字服务提供程序相互指示他们可以支持的 Windows 套接字的最高版本,并且每个都确认对方的最高版本是可接受的。 进入 WSPStartup 后,Windows 套接字服务提供程序将检查客户端请求的版本。 如果此版本等于或高于服务提供商支持的最低版本,则调用成功,并且服务提供程序在 WSPDATA 结构的 wHighVersion 成员中返回它支持的最高版本,在 wVersion 成员中返回其高版本和 wVersionRequested 参数中指定的最低版本。 然后,Windows 套接字服务提供程序假定 Windows 套接字 SPI 客户端将使用 wVersion 成员中指定的 Windows 套接字版本。 如果 WSPDATA 结构的 wVersion 成员对调用方来说是不可接受的,则它应调用 LPWSPCleanup 并搜索另一个 Windows 套接字服务提供程序或无法初始化。

此协商允许 Windows 套接字服务提供程序和 Windows 套接字 SPI 客户端支持一系列 Windows 套接字版本。 如果版本范围有任何重叠,客户端可以成功利用 Windows 套接字服务提供程序。

Windows 套接字规范的当前版本为版本 2.2。 当前的 Winsock DLL Ws2_32.dll支持请求以下任一版本的 Windows 套接字规范的应用程序:

  • 1.0
  • 1.1
  • 2.0
  • 2.1
  • 2.2

若要完全访问更高版本的 Windows 套接字规范的新语法,应用程序必须协商此更高版本。 在这种情况下, wVersionRequested 参数应设置为请求版本 2.2。 应用程序还必须完全符合更高版本的 Windows 套接字规范,例如针对适当的头文件进行编译、与新库链接或其他特殊情况。 Microsoft Windows 软件开发工具包 (Windows SDK) (SDK) 随附了 Winsock 2 支持的 Winsock2.h 头文件。

Windows Server 2008、Windows Vista、Windows Server 2003、Windows XP、Windows 2000、Windows NT 4.0 service Pack 4 (SP4) 及更高版本、Windows Me、Windows 98 和 Windows 95 OSR2 支持 Windows 套接字版本 2.2。 在 上也支持 Windows 套接字版本 2.2
带有 Windows 套接字 2 更新的 Windows 95。 这些平台上的应用程序通常应相应地设置 wVersionRequested 参数来请求 Winsock 2.2。

在 Windows 95 和 Windows NT 3.51 及更早版本中,Windows 套接字版本 1.1 是受支持的 Windows 套接字规范的最高版本。

编写的应用程序或 DLL 使用 Winsock DLL 支持的较低版本的 Windows 套接字规范使用 WSPStartup 函数成功协商此较低版本是合法的,并且有可能。 例如,应用程序可以在具有 Winsock 2.2 DLL 的平台上请求传递给 WSPStartup 函数的 wVersionRequested 参数中的版本 1.1。 在这种情况下,应用程序应仅依赖于符合所请求版本的功能。 不应使用新的 Ioctl 代码、现有函数的新行为和新函数。 WSPStartup 提供的版本协商主要用于允许为 Windows 95 和 Windows NT 3.51 及更早版本开发的旧版 Winsock 1.1 应用程序在更高版本的 Windows 上以相同的行为运行。 winsock 1.1 支持的 Winsock.h 头文件包含在 Windows SDK中。

下图提供了 WSPStartup 如何与不同 WS2_32.DLL 和 Windows 套接字服务提供程序结合使用的示例, (SP) 版本。

DLL
 
versions
SP
 
versions
wVersionRequested wVersion wHighVersion 最终结果
1.1 1.1 1.1 1.1 1.1 use 1.1
1.0 1.1 1.0 1.1 1.0 1.0 use 1.0
1.0 1.0 1.1 1.0 1.0 1.1 use 1.0
1.1 1.0 1.1 1.1 1.1 1.1 use 1.1
1.1 1.0 1.1 1.0 1.0 DLL 失败
1.0 1.1 1.0 --- --- WSAVERNOTSUPPORTED
1.0 1.1 1.0 1.1 1.1 1.1 1.1 use 1.1
1.0 1.1 2.0 1.1 2.0 1.1 1.1 use 1.1
1.0 1.1 2.0 2.0 2.0 2.0 2.0 使用 2.0
1.0 1.1 2.0 2.1 2.2 2.2 2.2 2.2 2.2 use 2.2
 

以下代码片段演示了仅支持 Windows 套接字 SPI 版本 2 的 Windows 套接字 SPI 客户端如何进行 WSPStartup 调用:

WORD wVersionRequested;
WSPDATA WSPData;
 
int err;
 
WSPUPCALLTABLE upcallTable =
{ 
    /* initialize upcallTable with function pointers */
};
 
LPWSPPROC_TABLE lpProcTable =
{ 
    /* allocate memory for the ProcTable */
};
 
wVersionRequested = MAKEWORD( 2, 2 );
 
err = WSPStartup( wVersionRequested, &WSPData, lpProtocolBuffer, upcallTable, lpProcTable );
if ( err != 0 ) {
    /* Tell the user that we could not find a usable */
    /* Windows Sockets service provider.                     */
    return;
}
 
/* Confirm that the Windows Sockets service provider supports 2.2.*/
/* Note that if the service provider supports versions */
/* greater than 2.2 in addition to 2.2, it will still */
/* return 2.2 in wVersion since that is the version we  */
/* requested.                                           */
 
if ( LOBYTE( WSPData.wVersion ) != 2 ||
         HIBYTE( WSPData.wVersion ) != 2 ) {
    /* Tell the user that we could not find a usable */
    /* Windows Sockets service provider.                     */
    LPWSPCleanup( );
    return;   
}
 
/* The Windows Sockets service provider is acceptable. Proceed. */

此代码片段演示了仅支持版本 2.2 的 Windows 套接字服务提供程序如何执行 WSPStartup 协商:

/* Make sure that the version requested is >= 2.2.  */
/* The low byte is the major version and the high   */
/* byte is the minor version.                       */
 
if ( (LOBYTE( wVersionRequested ) < 2) ||
     ((LOBYTE( wVersionRequested ) == 2) &&
     (HIBYTE( wVersionRequested ) < 2))) {
    return WSAVERNOTSUPPORTED;
}
 
/* Since we only support 2.2, set both wVersion and  */
/* wHighVersion to 2.2.                              */
 
lpWSPData->wVersion = MAKEWORD( 2, 2 );
lpWSPData->wHighVersion = MAKEWORD( 2, 2 );


Windows 套接字 SPI 客户端成功调用 WSPStartup 后,可以根据需要继续进行其他 Windows 套接字 SPI 调用。 使用完 Windows 套接字服务提供程序的服务后,客户端必须调用 LPWSPCleanup ,以便允许 Windows 套接字服务提供商释放为客户端分配的任何资源。

每个客户端进程必须至少调用 一次 WSPStartup 函数,并且可由 Winsock 2 DLL 或其他实体多次调用。 每次成功的 WSPStartup 调用都必须调用匹配的 LPWSPCleanup 函数。 服务提供商应按进程维护引用计数。 在每个 WSPStartup 调用中,调用方可以指定服务提供商 DLL 支持的任何版本号。

服务提供商必须存储指向客户端的httpall dispatch表的指针,该表由 WSPStartup 函数按进程接收为“刚果”表参数。 如果给定进程多次调用 WSPStartup ,则服务提供商必须仅使用最近提供的httpall调度表指针。

如果需要多次获取 WSPDATA 结构信息,Windows 套接字 SPI 客户端可以多次调用 WSPStartup 。 在每次此类调用中,客户端都可以指定提供程序支持的任何版本号。

必须有一个 LPWSPCleanup 调用对应于每个成功的 WSPStartup 调用,以允许第三方 DLL 使用 Windows 套接字提供程序。 这意味着,例如,如果 WSPStartup 被调用三次,则对 LPWSPCleanup 的相应调用必须发生三次。 对 LPWSPCleanup 的前两个调用除了递减内部计数器外,什么都不做。最终 的 LPWSPCleanup 调用执行所有必要的资源解除分配。

如果客户端是 16 位 Windows 套接字 1.1 客户端,则可以在作为 16 位进程启动的线程中调用此函数 (和大多数其他服务提供程序函数) 。 16 位进程的一个重要限制是 16 位进程无法创建线程。 对于计划将内部服务线程用作实现的一部分的服务提供程序实现者而言,这一点非常重要。

幸运的是,通常只有两个服务线程条件强的领域:

这两个区域只能通过新的 Windows 套接字 2 函数访问,后者只能由 32 位进程调用。

如果仔细遵循以下两个设计规则,则可以安全地使用服务线程:

  • 仅将服务线程用于 16 位 Windows 套接字 1.1 客户端不可用的功能。
  • 仅按需创建服务线程。

使用内部服务线程时,还有一些其他注意事项。 首先,线程通常会带来一些性能损失。 尽可能少地使用,并尽可能避免线程转换。 其次,代码应始终检查创建线程时出现错误,并 (正常且信息性地失败,例如,WSAEOPNOTSUPP) ,以防某些执行事件导致 16 位进程执行需要线程的代码路径。

分层服务提供程序提供此函数的实现,但在调用 WSPStartup 以初始化协议链中的下一层时,它也是此函数的客户端。 对下一层 WSPStartup 的调用可能会在执行此层的 WSPStartup 期间发生,或者可能会延迟并按需调用,例如调用 LPWSPSocket 时。 在任何情况下,此函数的 lpProtocolInfo 参数都适用一些特殊注意事项,因为它通过协议链的层向下传播。

分层提供程序通过搜索层自己的目录条目 ID) 和链中下一个元素的标识,搜索 lpProtocolInfo 引用的结构的 ProtocolChain,以确定其在链 (中自己的位置。 如果下一个元素是另一个层,则在调用下一层的 WSPStartup 时,此层必须向下一层传递一个 lpProtocolInfo,该 lpProtocolInfo 引用具有相同未修改链信息的相同未修改 WSAProtocol_Info 结构。 但是,如果下一层是基本协议 (即链) 中的最后一个元素,则此层在调用基本提供程序的 WSPStartup 时执行替换。 在这种情况下,lpProtocolInfo 参数应引用基提供程序的WSAPROTOCOL_INFO结构。

此策略的一个重要好处是基础服务提供商不必了解协议链。

当通过其他函数(如 LPWSPAddressToString、LPWSPDuplicateSocket、LPWSPSocket 或 LPWSPStringToAddress)的分层序列传播WSAPROTOCOL_INFO结构时,将应用相同的传播策略。

要求

要求
最低受支持的客户端 Windows 2000 Professional [仅限桌面应用]
最低受支持的服务器 Windows 2000 Server [仅限桌面应用]
目标平台 Windows
标头 ws2spi.h

另请参阅

WSAProtocol_Info

LPWSPAddressToString

LPWSPStringToAddress

LPWSPCleanup

LPWSPDuplicateSocket

LPWSPEventSelect

WSPProc_Table

LPWSPSend

LPWSPSendTo

LPWSPSocket

WSPUpCallTable