《Windows+网络编程技术(十四)Windows_网络编程技术(十.pdf》由会员分享,可在线阅读,更多相关《Windows+网络编程技术(十四)Windows_网络编程技术(十.pdf(34页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、下载第14章 Winsock 2 服务提供者接口Winsock 2服务提供者接口(Service Provider Interface,SPI)代表着另一端的Wi n s o c k编程(和Winsock 2API相对应)。Wi n s o c k的一端是A P I,另一端则是S P I。自第6章到第1 3章,我们已对 Winsock 2 API 进行了详细讨论。Winsock 2是围绕着 Wi n d o w s开放系统架构(Windows Open System Architecture,W O S A)来设计的,W O S A在Wi n s o c k和Wi n s o c k应用程序之
2、间有一个标准 A P I;在Wi n s o c k和Wi n s o c k服务提供者(比如 T C P/I P)之间有一个标准的S P I。图1 4-1展示了W s 2 _ 3 2.d l l,即Winsock 2支持的动态链接库(D L L)在Wi n s o c k应用程序和Wi n s o c k服务提供者之间的分布情况。本章详细地讲解了 Winsock 2 SPI。在结束本章的学习时,大家自然便理解如何开发服务提供者,进一步扩展 Winsock 2的能力。图14-1 Winsock 2的WOSA架构14.1 SPI基础Winsock 2 SPI允许开发两类服务提供者传输提供者和名字
3、空间提供者。“传输提供者”(Transport providers,一般称作协议堆栈,比如 T C P/I P)即能够提供建立通信、传输数据、日常数据流控制和错误控制等等功能的服务。“名字空间提供者”(Name space providers)则把一个网络协议的定址属性和一个或多个用户友好名关联到一起,以便启用与协议无关的名字解析方案。服务提供者不外乎就是 Wi n 3 2支持的D L L,挂靠在Winsock 2的W s 2 _ 3 2.d l l模块下。对Winsock2 API中定义的许多内部调用来说,这些服务提供者都提供了它们的运作方式。Winsock 2应用程序Winsock 2应用
4、程序名字空间函数The Winsock 2 DLLWs2_32.dll(32-bit)传输函数传输服务提供者Winsock 2传输服务提供者接口传输服务提供者名字空间提供者名字空间提供者Winsock 2名字空间提供者接口364计计第二部分附Winsock API下载14.1.1 SPI命名规则Winsock 2 SPI函数原型采用下面的函数前缀命名规则:W S P(Wi n s o c k提供者):用于传送服务提供者函数。N S P(名字空间提供者):用于名字空间提供者函数。W P U(Wi n s o c k提供者上调):供服务提供者调用的W s 2 _ 3 2.d l l支持函数使用。W
5、 S C(Wi n s o c k配置):供在Winsock 2中安装服务提供者的函数使用。举个例子来说,一个名为W S A I n s t a l l P r o v i d e r的函数,仅仅是一个S P I配置函数。14.1.2 Winsock 2 API和SPI函数之间的映射多数情况下,一个应用程序在调用 Winsock 2函数时,W s 2 _ 3 2.d l l会调用相应的Wi n s o c kS P I函数,利用特定的服务提供者执行所请求的服务。举个例子来说,s e l e c t对应W S P S e l e c t,W S A C o n n e c t对应W S P C
6、o n n e c t,而W S A A c c e p t则对应W S PA c c e p t。然而,并非所有的Wi n s o c k函数都有对应的S P I函数。下面列出了这些例外情况。h t o n l、h t o n s、n t o h l和n t o h s这一类的支持函数在W s 2 _ 3 2.d l l内部执行,没向下传给服务提供者。这一点对这些函数的W S A版本来说,也不例外。像i n e t _ a d d r和i n e t _ n t o a这样的I P转换函数只能在W s 2 _ 3 2.d l l内执行。Winsock 1.1中,所有由I P决定的名字转换和解
7、析函数(比如g e t X b y Y、W S A A s y n G e t X B y Y、W S A C a n c e l A s y n c R e q u e s t以及g e t h o s t n a m e)都在W s 2 _ 3 2.d l l内部执行。Wi n s o c k服务提供者列举和与锁定挂钩相关的函数都在 W s 2 _ 3 2.d l l内部执行。因此,W S A E n u m P r o t o c o l s、W S A I s B l o c k i n g、W S A S e t B l o c k i n g H o o k和W S A U n h
8、 o o k B l o c k i n g没有相应的S P I函数。Wi n s o c k错误代码的管理在W s 2 _ 3 2.d l l内部进行。而S P I中,不需要W S A G e t L a s t E r o r和W S A S e t L a s t E r r o r。事件对象处理和等待函数,其中包括W S A C r e a t e E v e n t、W S A C l o s e E v e n t、W S A S e t E v e n t、W S A R e s e t E v e n t和W S AWa i t F o r M u l t i p l e E
9、v e n t s,这些函数直接映射成原始的 Wi n 3 2操作系统调用,没有出现在S P I中。现在,大家准备学习哪些 Winsock API映射成Winsock 2服务提供者。在开发服务提供者时,大家将看到定义在包容文件W s 2 s p i.h中的所有S P I函数原型。14.2 传输服务提供者Winsock 2中使用的传输服务提供者有两类:基础服务提供者和分层服务提供者。基础服务提供者执行网络传输协议(比如 T C P/I P)的具体细节其中包括在网络上收发数据之类的核心网络协议功能。“分层式”(L a y e r e d)服务提供者只负责执行高级的自定义通信功能,并依靠下面基础服务
10、提供者,在网络上进行真正的数据交换。举个例子来说,你可以在现成的基础T C P/I P提供者上执行一个数据安全管理者或带宽管理者。图1 4-2展示了如何在一个W s 2 _ 3 2.d l l和一个基础提供者之间安装一个或多个分层式提供者。本小节的重点在于如何开发分层式传输服务提供者。如果你此时正在开发一个基础服务提供者,就可以运用这里的规则。我们具体讲解如何从头执行特定 S P I函数。举个例子来说,我们不提供WSPSend SPI函数是如何把数据写入网络适配器这类的细节。相反,我们展示的则是分层式提供者的W S P S e n d函数将如何调用低级提供者的 W S P S e n d函数,
11、这是多数分层式服务提供者的一项基本要求。从本质上说,开发一个分层式服务提供者所涉及的许多操作都依赖于你的提供者对你的下一层提供者进行的S P I调用来完成。容易出错的环节是通过Winsock I/O模型,怎样对I/O调用(参见第8章)进行处理,至于这一点,我们稍后将继续讨论。本书的配套光盘上,我们提供了一个示例,名为 L S P,向大家演示了如何执行分层式协议提供者,该提供者只计下了一个套接字上利用 I P传输协议传输了多少字节。微软平台 S D K特别提供了一个更高级的分层式协议提供者示例,名为 l a y e r e d(分层式),可在M S D N平台S D K示例中找到它。至于 M S
12、 D N平台 S D K示例则在 f t p:/f t p.m i c r o s o f t.c o m/b u s s y s/Wi n S o c k/w i n s o c k 2/l a y e r e d.z i p下载。注意上面我们常提到这些术语“S P I客户机”和“低级别提供者”。S P I客户机既可以是Winsock 2的W s 2 _ 3 2.d l l,又可以是位于你的服务提供者之上的另一个分层式服务提供者。S P I客户机绝不可能是Wi n s o c k应用程序本身,因为Wi n s o c k应用程序必须使用W s 2 _ 3 2.d l l中导出的Winsock
13、 2 API。“低级别提供者”这个术语只能在描述分层式服务提供者的开始时使用。低级别提供者既可以是另查个分层式服务提供者,又可以是基础服务器提供者。正如大家即将看到的那样,一台机器上可以安装若干个分层式服务提供者;因此,也可以在你的提供者下面,再安装一个分层式服务提供者。图14-2 分层提供者的架构14.2.1 WSPStartupWinsock 2传输服务提供者随标准的Wi n d o w s动态链接库模块一起执行,你必须把 D l l M a i n函数导入这个动态链接库模块中。除此以外,还必须导入一个名为 W S P S t a r t u p的单一函数条目。在调用者(如S P I客户机
14、)调用W S P S t a r t u p时,便通过一个被当作参数投送的函数派遣表打开另外的3 0个S P I函数,传输服务提供者便由这 3 0个函数组成。函数派遣表参见表 1 4-1。你的服务提供者必须提供对W S P S t a r t u p函数和其他3 0个函数的支持。何时以及怎样调用 W S P S t a r u p呢?这个问题尤其重要。也许应用程序调用 W S A S t a r t u pA P I时,你也在考虑调用W S P S t a r t u p。这里的情况有所不同。调用 W S A S t a r t u p期间,Wi n s o c k不知道需要使用哪种服务提供者
15、的类型。Wi n s o c k根据W S A S o c k e t调用的地址家族、套接字类第14章计Winsock 2 服务提供者接口计计365下载APISPISPI分层提供者基本提供者分层提供者Ws2_32.dllSPI型和协议参数,决定需要加载哪个服务提供者。只有在一个应用程序通过 s o c k e t或W S A S o c k e tA P I调用建立一个套接字时,Wi n s o c k才会调用一个服务提供者。举个例子来说,如果一个应用程序建立了一个采用地址家族 A F _ I N E T、套接字类型S O C K _ S T R E A M的套接字,Wi n s o c k就
16、搜索并加载与之相应的、能够提供 T C P/I P能力的传输提供者。我们将在本章的 1 4.2.7节“传输服务提供者的安装”就此进行深入讨论。表14-1 传输服务提供者的支持函数A P I函数对应的S P I函数W S A A c c e p t(a c c e p t也可间接映射成W S PA c c e p t)W S PA c c e p tW S A A d d r e s s To S t r i n gW S PA d d r e s s To S t r i n gW S A A s y n c S e l e c tW S PA s y n c S e l e c tb i n
17、 dW S P B i n dW S A C a n c e l B l o c k i n g C a l lW S P C a n c e l B l o c k i n g C a l lW S A C l e a n u pW S P C l e a n u pc l o s e s o c k e tW S P C l o s e S o c k e tW S A C o n n e c t(c o n n e c t也可间接映射成W S P C o n n e c t)W S P C o n n e c tW S A D u p l i c a t e S o c k e tW S
18、 P D u p l i c a t e S o c k e tW S A E n u m N e t w o r k E v e n t sW S P E n u m N e t w o r k E v e n t sW S A E v e n t S e l e c tW S P E v e n t S e l e c tW S A G e t O v e r l a p p e d R e s u l tW S P G e t O v e r l a p p e d R e s u l tg e t p e e r n a m eW S P G e t P e e r N a m eg
19、e t s o c k n a m eW S P G e t S o c k N a m eg e t s o c k o p tW S P G e t S o c k O p tW S A G e t Q O S B y N a m eW S P G e t Q O S B y N a m eW S A I o c t lW S P I o c t lW S A J o i n L e a fW S P J o i n L e a fl i s t e nW S P L i s t e nW S A R e c v(r e c v也可间接映射成W S P R e c v)W S P R e
20、c vW S A R e c v D i s c o n n e c tW S P R e c v D i s c o n n e c tW S A R e c v F r o m(r e c v f r o m也可间接映射成W S P R e c v F r o m)W S P R e c v F r o ms e l e c tW S P S e l e c tW S A S e n d(s e n d也可间接映射成W S P S e n d)W S P S e n dW S A S e n d D i s c o n n e c tW S P S e n d D i s c o n n
21、e c tW S A S e n d To(s e n d t o也可间接映射成W S P S e n d t o)W S P S e n d Tos e t s o c k o p tW S P S e t S o c k O p ts b u t d o w nW S P S b u t d o w nW S A S o c k e t(s o c k e t也可间接映射成W S P S o c k e t)W S P S o c k e tW S A S t r i n g To A d d r e s sW S P S t r i n g To A d d r e s s14.2.2
22、参数在初始化传输服务提供者时,关键性的函数便是 W S A S t a r t u p。它的定义如下:366计计第二部分附Winsock API下载第14章计Winsock 2 服务提供者接口计计367下载w Ve r s i o n R e q u e s t e d参数用于取得调用者能够使用的 Windows Sockets SPI支持函数的最新版本。你的服务提供者应该对这个值进行检查,以便得知它是否支持所请求的版本。你的提供者通过一个W S P D ATA结构,利用l p W S P D a t a参数返回关于它自己的版本信息。W S P D ATA结构的格式如下:w Ve r s i
23、o n参数中,协议提供者必须返回调用者希望采用的 Wi n s o c k版本号。w H i g h Ve r s i o n参数必须返回提供者支持的 Wi n s o c k的最高版本。这个值一般和 w Ve r s i o n的值相同(关于Wi n s o c k版本信息,详见第7章)。s z D e s c r i p t i o n字段返回一个空中止 U N I C O D E字串,该字串把你的提供者视作S P I客户机。这个字段最多可容纳2 5 6个字符。W S P S t a r t u p的l p P r o t o c o l I n f o参数是一个指针,指向一个 W S A
24、 P R O TO C O L _ I N F O W结构。该结构中包含了和提供者有关的特征信息(协议特征和这个结构的详细情况,参见第5章“Wi n s o c k协议信息”)。W S A P R O TO C O L _ I N F O W结构中的信息是W s 2.3 2 _ d l l从Winsock 2服务提供者目录中检索得来的。这个目录中包含了服务提供者的属性信息。我们将在“传输服务提供者的安装”这一小节,对Winsock 2目录条目做进一步的探讨。在开发分层式服务提供者时,需要以一种独特的方式来处理 l p P r o t o c o l I n f o这个参数,因为它包含的信息关系
25、到你的服务提供者在 W s 2 _ 3 2.d l l和基础服务提供者之间,是怎样分布的。这个参数用于决定你的服务提供者之下的那个服务提供者(既可以是另一个分层提供者,又可以是一个基础提供者)。从某个角度来说,你的提供者必须通过加载下一个提供者的 D L L模块和调用它的 W S P S t a r t u p函数这一方式,来加载下一个提供者。l p P r o t o c o l I n f o指向的W S A P R O TO C O L _ I N F O W结构中包含一个字段P r o t o c o l C h a i n,该字段标志你的服务提供者和机器上的其他提供者是如何排序的。P
26、 r o t o c o l C h a i n字段实际上是一个W S A P R O TO C O L C H A I N结构,它的格式如下:C h a i n L e n字段标志W s 2 _ 3 2.d l l和基础的服务提供者之间,重叠了多少层(这个数包含基础提供者在内)。如果你有一台这样的机器,在一个协议之上只有一个重叠服务提供者,比如说T C P/I P,那么这个字段就应该是 2。C h a i n E n t r i e s字段是一数组,该数组由服务提供者目录标志号组成,这些编号唯一性地标志出重叠服务提供者,这些提供者因为某一特定协议而链接到一起。我们将在1 4.2.7节“传输服
27、务提供者的安装”中详细说明 W S A P R O TO C O L C H A I N结构。分层式服务提供者的一项要求是搜索 P r o t o c o l C h a i n字段,以便决定它自己在服务提供者数组中所处的位置(通过搜索层目录条目这一方式),以及确定数组中的下一个提供者。如果下一个提供者是另一层,就必须把未经修改的 l p P r o t o c o l I n f o结构投给下一层的W S P S t a r t u p函数。如果下一层提供者是本数组中的最后一位(即基础提供者),你的提供者就必须在调用基础提供者的W S P S t a r t u p函数之前,利用这个基础提供
28、者的 W S A P R O TO C O L _ I N F O W结构,在l p P r o t o c o l I n f o结构上执行交换。程序清单 1 4-1演示了分层提供者应该怎样通过编程来管理l p P r o t o c o l I n f o结构。程序清单14-1 为W S P S t a r t u p寻找相应的W S A P R O TO C O L _ I N F O W结构368计计第二部分附Winsock API下载W S P S t a r t u p的U p c a l l Ta b l e取得W s 2 _ 3 2.d l l的S P I上调派遣表,表中包含了
29、指向许多支持函数的指针,你的提供者可利用这些函数来管理提供者自身和 Winsock 2之间的I/O操作。本章的“Winsock I/O模型支持”小节中,我们还定义许多此类的函数,并对它们的用法进行了描述。W S P S t a r t u p的最后一个参数是l p P r o c Ta b l e,代表一个表,表内有3 0个S P I函数指针,你的服务提供者必须能够提供对这些函数的支持。这 3 0个函数列在表1 4-1中。每个S P I函数都遵照自己对应的A P I函数的参数说明。每个函数都提供一个终极参数,l p E r r n o,在实施失败时,你的提供者必须用这个参数报告具体的Wi n
30、s o c k错误代码。举个例子来说,如果你在实施 W S P S e n d,但不能为它分配内存,可能就会返回W S A E N O B U F错误代码。S P I函数W S P S e n d、W S P S e n d To、W S P R e c v、W S P R e c v F r o m以及W S P I o c t l,都突出了这个额外的参数:l p T h r e a d I d,它标志调用了S P I函数的应用程序线程。稍后,我们将看到,这个特性对支持完成例程时,发挥了很大的作用。最后一个需要注意的是几个 Winsock 1.1函数,比如 s e n d和r e c v,直
31、接映射成相应的Winsock 2函数。我们之所以说这些 Winsock 1.1间接映射成相应的S P I函数,是因为它们事实上调用了提供类似功能的 Winsock 2函数。比如说,s e n d函数实际上调用的是W S A S e n d函数,W S A S e n d函数的映射函数是W S P S e n d。表1 4-1中,我们特别注明了间接映射成 S P I函数的A P I函数。14.2.3 实例计数在Wi n s o c k规格中,应用程序调用 W S A S t a r t u p和W S A C l e a n u p函数的次数是没有限制的。你的服务提供者的W S P S t a
32、r t u p和W S P C l e a n u p函数也将和它们对应的 A P I函数一样,调用的次数相当。如此一来,你的服务提供者就应该保留一个实例计数,以便了解 W S P S t a r t u p函数被调用了多少次,再相应地调用 W S P C l e a n u p多少次,以便抵消W S P S t a r t u p被调用的次数。保留实例次数的目的在于:允许你的服务提供者的启用和清除过程合乎情理。举个例子来说,只要你的实例计数大于 0,你的提供者就可以一直保存在内存中。当实例计数落到0以下时,W s 2 _ 3 2.d l l最终从相应的内存中卸载你的提供者。14.2.4 套接
33、字句柄当S P I客户机调用W S P S o c k e t、W S PA c c e p t和W S P J o i n t L e a f函数时,服务提供者必须返回套接字句柄。返回 S P I客户机的套接字句柄既可以是可安装文件系统(I F S)句柄,又可以是第14章计Winsock 2 服务提供者接口计计369下载非I F S句柄。如果一个服务提供者返回的是 I F S句柄,就会被视作 I F S提供者;反之,就是非I F S提供者。微软的基础传输提供者全都是 I F S句柄。设计Wi n s o c k的目的是允许Wi n s o c k应用程序利用Win32 API函数R e a
34、d F i l e和Wr i t e F i l e,在套接字句柄上收发数据。因此,必须考虑到如何在一个服务提供者内建立套接字句柄。如果在开发服务提供者的同时,还试图为套接字句柄上调用 R e a d F i l e和Wr i t e F i l e的Wi n s o c k应用程序提供服务,就要考虑另行开发一个 I F S提供者。但之前,必须先了解I/O的某些限制。1.IFS提供者我们在前面曾提过,传输服务提供者可以是分层的或基础的。如果正在开发一个基础的I F S提供者,你的提供者就会有一个核心模式的操作系统组件,而这个组件启用了 Wi n s o c k提供者来建立句柄,与R e a d
35、 F i l e和Wr i t e F i l e函数中的文件系统句柄相同。核心模式软件的开发不在本书讨论之列。如果想了解如何开发核心模式操作系统组件这方面的详情,可参考M S D N设备开发工具包(Device Development Kit,D D K)。分层式服务提供者也可变成 I F S提供者,但前提是它必须位于现成的基础 I F S提供者顶部。这涉及到把低级I F S提供者的套接字句柄(在你的分层提供者中检索得来的)直接上传到你的S P I客户机。从一个低级提供者直接上传套接字句柄会限制了分层提供者的能力,主要表现在以下两方面:如果在一个套接字上调用了 R e a d F i l e
36、和Wr i t e F i l e,便不会调用分层提供者的 W S P S e n d和W S P R e c v函数。这些函数将绕过分层提供者,直接调用基础 I F S提供者的实施。分层提供者将不能后处理提交到一个完成端口的重叠 I/O请求。完成端口的后处理完成绕过了分层式提供者。如果你的分层式提供者试图对通过这个提供者传递的所有 I/O操作进行监视,还必须开发一个非I F S分层式提供者,我们稍后对此进行详细讨论。只要一个I F S提供者(分层的或基础的)建立了一个新的套接字描述符,就需要要求它调用W P U M o d i f y I F S H a n d l e,而不是提供指向 S
37、P I客户机的新句柄。Wi n 3 2 A P I函数(比如R e a d F i l e和Wr i t e F i l e)在一个套接字上执行I/O时,这样便可使Winsock Ws2_32.dll合理地标识与指定套接字关联到一起的I F S服务提供者进程。W P U M o d i f y I F S H a n d l e的定义如下:d w C a t a l o g E n t r y I d参数标识你的服务提供者的目录I D。P r o p o s e d H a n d l e参数代表一个I F S句柄,该句柄是你的服务提供者分配的(在基础提供者的情况下)。如果此时正在开发分层式I
38、 F S提供者,这个句柄就会从低级提供者上传。如果这个函数失败,返回错误 I N VA L I D _ S O C K E T,l p E r r n o参数便取得特定的Wi n s o c k错误代码信息。2.非I F S提供者如果你此时正在开发分层式提供者,并试图对一个套接字上发生的所有读取和写入操作进行监视,还必须开发一个I F S提供者。非I F S提供者使用上调函数W P U C r e a t e S o c k e t H a n d l e建立套接字句柄。W P U C r e a t e S o c k e t H a n d l e建立的套接字句柄类似于 I F S提供者句
39、柄,两者均允许Wi n s o c k应用程序在套接字上使用R e a d F i l e和Wr i t e F i l e函数。但是,这两个函数对I/O性能有370计计第二部分附Winsock API下载一个非常明显的不利影响,因为 Winsock 2架构必须分别执行到服务提供者的 W S P R e c v和W S P S e n d函数的重定向I/O操作。W P U C r e a t e S o c k e t H a n d l e的定义如下:d w C a t a l o g E n t r y I d标识你的服务提供者的目录 I D。d w C o n t e x t参数允许你自
40、由地把提供者的数据和一个套接字描述符关联到一起。在本书配套光盘上的 L S P示例中,我们利用了这个字段保存了收发数据的字节数。Wi n s o c k提供了一个上调函数 W P U Q u e r y S o c k e t H a n d l e C o n t e x t,该函数用于取得保存在d w C o n t e x t中关联的套接字提供者数据,它的定义如下:s参数代表套接字句柄,该句柄从一个 S P I客户机(最初通过W P U C r e a t e S o c k e t H a n d l e建立的)开始下传,并且你打算用这个套接字句柄取得套接字提供者的数据。l p C o
41、 n t e x t参数取得最初投入W P U C r e a t e S o c k e t H a n d l e中的提供者数据。和前一个函数中的 l p E r r n o参数一样,若函数调用失败,就会收到相关的 Wi n s o c k错误代码。如果W P U C r e a t e S o c k e t H a n d l e失败,便返回I N VA L I D _ S O C K E T;若W P U Q u e r y S o c k e t H a n d l e C o n t e x t失败,则返回S O C K E T _ E R R O R。14.2.5 Winsoc
42、k I/O模型支持通过第8章的学习,大家已经知道 Wi n s o c k的特别突出了几个I/O模型,这些模型可以用来管理套接字上的 I/O操作。从服务提供者角度来看,每个模型都要求使用某些 S P I上调函数,这些函数是W s 2 _ 3 2.d l l提供的,通过前面提到的 W S P S t a r t u p中的U p c a l l Ta b l e参数使用。如果此时正在开发一个简单的 I F S分层式提供者,下面几个小节中讲的 I/O模式遵守的原则就不适用,因为低级提供者便足以应付对各个模式的 I/O操作的管理了。这些原则只适用于其他类的提供者。我们将重点讨论如何开发非 I F S
43、分层式服务提供者。1.锁定和非锁定模型Winsock 2中,锁定I/O是最简单的。锁定套接字的任何一个 I/O操作都不会在操作出完成之前返回。因此,所有线程一次只能执行一个 I/O操作。举个例子来说,一个 S P I客户机以锁定方式调用 W S P R e c v函数时,你的提供者只需要把这个调用直接传给下一个提供者的W S P R e c v调用。对你的提供者而言,它的 W S P R e c v函数只能在下一个提供者的 W S P R e c v函数完成时,才能够返回。尽管锁定I/O模型非常易于实现,但仍然需要考虑向后兼容Winsock 1.1锁定挂钩这一问题。Winsock 2 API规
44、格中已经删除了W S A S e t B l o c k i n g C a l l和WSACancelBlocking API调用。但是,一个Winsock 1.1应用程序在调用 W S A S e t B l o c k i n g H o o k和W S A C a n c e l B l o c k i n g C a l l时,W s 2 _ 3 2.d l l仍然可以调用 W S P C a n c e l B l o c k i n g H o o k。在分层式服务提供者中,只需要把W S P C a n c e l B l o c k i n g H o o k调用传给基础提供
45、者的相应调用即可。如果此时正在执行一个基础提供者和一个锁定调用,就必须执行周期性地调用 W P U Q u e r y B l o c k i n g C a l l b a c k函数这一机制。第14章计Winsock 2 服务提供者接口计计371下载372计计第二部分附Winsock API下载W P U Q u e r y B l o c k i n g C a l l b a c k的定义如下:像我们在介绍W S P S t a r t u p函数时描述的那样,d w C a t a l o g E n t r y I d参数取得你的提供者的目录I D。l p l p f n C a
46、l l b a c k参数是一个函数指针,指向应用程序的锁定挂钩函数,你必须周期性地调用这个函数(即回调函数),以避免该应用程序的锁定调用真正地被锁定。这个回调函数的形式如下:你的提供者周期性调用 l p l p f n C a l l b a c k时,便把l p d w C o n t e x t参数的值投给该回调函数的d w C o n t e x t参数。W P U Q u e r y B l o c k i n g C a l l b a c k函数的最后一个参数是 l p E r r n o。若该函数返回S O C K E T _ E R R O R,这个参数便返回相应的Wi n
47、s o c k错误代码信息。2.select模型select I/O模型要求提供者为 W S P S e l e c t函数中的这几个参数(r e a d f d s、w r i t e f d s和e x c e p t f d s)管理f d _ s e t结构。W S P S e l e c t函数的定义如下:从本质上来说,f d _ s e t数据类型代表一个套接字集合。一个 S P I客户机利用W S P S e l e c t调用你的提供者时,便把套接字句柄投给这个集合中的一个或多个套接字。你的提供者负责判断列出的套接字上何时发生了网络活动。对非I F S分层提供者来说,便要求建立
48、三个 f d _ s e t数据字段,并将S P I客户机的套接字句柄映射到这个集合中的低层提供者的套接字句柄。一旦建立了所有的套接字集合,你的提供者便调用低层提供者上的 W S P S e l e c t。低层提供者的调用完成时,你的提供者必须判断各个f d _ s e t字段中,哪些套接字上有待发事件。此时,便可以用这个非常有用的上调函数W P U F D I s S e t,来判断设置了哪些基础提供者套接字。这个上调函数类似于 F D _ I S S E T宏(参见第8章),它的定义如下:s参数代表你正在套接字集合中查找的套接字。s e t参数是一个真正的套接字描述符集合。由于你的提供者
49、将检查投向低层提供者的每个描述符集合中的内容,因此,你的提供者应该保存上层提供者到低层提供者之间的套接字映射。低层提供者完成 W S P S e l e c t调用时,就可轻松地向上层提供者反映哪些套接字上有 I/O待发事件了。一旦决定了哪些低层提供者套接字有待发的网络事件,就必须更新原来的 f d _ s e t集合,这些集合是原来的 S P I客户机投递的。W s 2 s p i.h文件中提供了三个宏(F D _ C L R、F D _ S E T和F D _ Z E R O),它们可用于对原来的套接字集合进行管理。关于这些宏的说明,参见第 8章。程序清单1 4-2演示了怎样实施W S P
50、 S e l e c t。程序清单14-2 WSPSelect实施详解第14章计Winsock 2 服务提供者接口计计373下载3.WSAAsyncSelect模型WSAAsyncSelect I/O模型涉及到的管理中,包括对套接字上网络事件的Wi n d o w s消息通知进行管理。SPI客户机调用WSPAsyncSelect函数后,便可使用这个模型了。这个函数的定义如下:s参数代表S P I客户机的套接字,该套接字希望收到网络事件的窗口消息通知。h W n d参数标志窗口句柄,在套接字s上发生I E v e n t参数中定义的网络事件时,这个窗口句柄便接收 w M s g参数中定义的消息。