通信网络程序设计(王晓东西电版)第9章链接库技术

上传人:xiao****017 文档编号:22427170 上传时间:2021-05-25 格式:PPT 页数:90 大小:600.50KB
收藏 版权申诉 举报 下载
通信网络程序设计(王晓东西电版)第9章链接库技术_第1页
第1页 / 共90页
通信网络程序设计(王晓东西电版)第9章链接库技术_第2页
第2页 / 共90页
通信网络程序设计(王晓东西电版)第9章链接库技术_第3页
第3页 / 共90页
资源描述:

《通信网络程序设计(王晓东西电版)第9章链接库技术》由会员分享,可在线阅读,更多相关《通信网络程序设计(王晓东西电版)第9章链接库技术(90页珍藏版)》请在装配图网上搜索。

1、1第 9章 链 接 库 技 术9.1 链接库概述9.2 静态链接库9.3 动态链接库9.4 传输服务提供者小结 2 在程序设计过程中,往往需要重复使用一段或若干代码(函数或过程),这种需求叫做程序复用。程序复用采用的方法往往是将复用的代码集成为一个个方便调用的包,这种包可以是链接库、类库、COM包、插件、控件,等等。从本章开始,将先后介绍两种代码复用的集成技术,即链接库技术和MFC类库(见第10章)。本章介绍的链接库技术是一种非常有用的代码集成技术,对于代码的复用、软件的升级、调用的标准化、不同编程器的协同编程等都至关重要。 3 本章首先介绍链接库的概念,然后依次介绍静态和动态两种链接库的概念

2、、调用以及编写方法,继而针对网络中不同类型的动态链接库的调用,介绍了基于链接库技术的Winsock传输服务提供者(Service Provider Interface,SPI)编程。SPI编程为用户设计自己的通信协议、防火墙和木马程序提供了有效手段。 4 链接库是从C语言函数库和Pascal库单元的概念发展而来的。所有的C语言标准库函数都存放在某一函数库中,同时用户也可以用专用的程序创建自己的函数库。在库函数链接应用程序的过程中,链接器从库文件中拷贝程序调用的函数代码,并把这些函数代码添加到可执行文件中。9.1 链接库概述 5 目前链接库有静态和动态之分,二者的链接方法有所不同。如果采用静态链

3、接库,则lib中的指令全部都被直接包含在最终生成的EXE文件中了;若使用dll,则该dll不必被包含在最终的exe文件中,exe文件执行时可以“动态”地引用和卸载这个与exe独立的dll文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态链接库,而在动态链接库中还可以再包含其他的动态或静态链接库。 6 需要注意的是,头文件与库文件都包含函数,但二者存在以下区别:(1) 头文件由编译器使用,库文件由连接器使用;(2) 头文件中的函数为对应的库文件中的函数提供接口(ASCII码),一般包括函数声明、宏定义、类型定义等,库文件中放着函数实现代码编译后的结果(二

4、进制的机器码)。 7 9.2.1 静态链接库概念静态链接库不同于动态链接库(*.dll),在静态库情况下,函数和数据被编译进一个二进制文件(通常扩展名为*.lib),Visual C+的编译器在链接过程中将从静态库中恢复这些函数和数据并把它们和应用程序中的其他模块组合在一起生成可执行文件。这个过程称为“静态链接”,此时因为应用程序所需的全部内容都是从库中复制出来的,所以静态库本身并不需要与可执行文件一起发行。9.2 静态链接库 8 可以说,每一个lib文件就是若干函数(假设只有函数)的定义。完整的可调用的静态链接库最少提供两个文件,即静态库的头文件和静态库的lib文件。 9 9.2.2 静态链

5、接库设计创建一个静态链接库可以利用编译器的向导。以VC6.0为例,首先选择“FileNew”菜单,弹出“New”对话框;选择“Projects”标签,在项目类型列表框中选择“Win32 Static Library”项,在“Name”中输入“MyLib”,表明要创建一个MyLib.lib的静态库文件,最后选择“完成”。其他版本的VC编译器与这个过程区别不大。在工程中最少需要新建.h和.cpp两个文件,一个用于对要封装的函数进行声明,一个是函数的实现。下面两段程序就是MyLib.h和MyLib.ccp,封装了函数MyFunc()。 10 文件MyLib.h如下:#ifndef _MYMATH_H

6、 #define _MYMATH_H extern C int MyFunc(int n); /进行函数的声明/其他函数的声明 #endif 11 文件MyLib.ccp如下:#includeMyLib.h int MyFunc(int n) return n+=1003; 编译这个工程就得到了一个MyLib.lib文件,这个文件就是一个函数库,它提供了MyFunc功能。将头文件和.lib文件提交给用户后,用户就可以直接使用其中的函数了。 12 9.2.3 静态链接库调用调用静态链接库的方法有两种:一种是通过编译器中的工程设置实现调用,另一种是在程序代码中加入调用语句。两种调用方式都需要将要调

7、用的静态链接库的头文件采用“#include”方法加入文件。1工程设置调用在Win32环境下的VC+6.0编译器,以调用netapi32.lib静态链接库为例,在菜单中的“工程”下拉菜单的“设置”项的“Link”选项卡中加入netapi32.lib,如图9-1所示。 13图9-1 netapi32.lib设置 14 在VS2005中,工程调用设置分两步: 右键点击工程名testlib,选择“属性”,弹出“工程属性”框,然后选择“配置属性链接器常规附加库目录”选项,该选项就是用于设置lib所在目录的,添加的目录如图9-2所示; 选择“属性”项,弹出“工程属性”框,然后是“配置属性链接器常规附加依

8、赖”项,该选项就用于指定项目中需要用到的库文件(因为前面已经指定了库文件所在目录),如图9-3所示。 15 图9-2 VS2005的lib路径设置 16 图9-3 VS2005的文件设置 17 对于系统标准库(如包含函数printf的库文件),在程序中调用的时候只要把它的头文件“stdio.h”用“#include”加到程序里就可以了,不用再手工指定,连接器会在编译时自动连接它们,因而调用方法会与后面提及的方法稍有不同。 18 2程序代码调用除了上述在编译器中设置lib之外,还可以在使用程序代码中直接调用。使用如下语句进行静态链接库的调用时,应当注意该链接库应当放在编译器可以找到的位置,否则就

9、应当在文件名处把文件的路径写全(假设netapi32.lib放在根目录下)。#include stdafx.h#includeMyLib.h #pragma comment(lib,MyLib.lib) /#pragma comment(lib,C: MyLib.lib) 19 int main(int argc, char* argv)int a=MyFunc(2); printf (jiguo is %d,a); return 0; 这种调用方法比较适合其他程序员对程序源代码的阅读,同样也不适用于系统标准库 20 9.3.1 动态链接库概念动态链接库在Windows操作系统中,对于程序执行

10、是非常重要的,因为程序在执行的时候必须链接到dll文件,才能够正确地运行,而有些dll文件可以被许多程序共用。因此,程序设计人员可以利用dll文件,使程序不至于太过巨大。但是当安装的程序越来越多时,dll文件也就会越来越多,当用户删除程序的时候,如果没有用的dll文件没有被删除的话,久而久之就会造成系统的负担。9.3 动态链接库 21 使用动态链接库的一些好处是:(1) 多个应用程序共享代码和数据。比如Office软件的各个组成部分有相似的外观和功能,这就是通过共享动态链接库实现的。(2) 在钩子(挂钩)程序过滤系统消息时必须使用动态链接库。(3) 动态链接库以一种自然的方式将一个大的应用程序

11、划分为几个小的模块,这有利于小组内部成员的分工与合作,并且各个模块还可以独立升级。如果小组中的一个成员开发了一组实用例程,他就可以把这些例程放在一个动态链接库中,让小组的其他成员使用。 22 (4) 为了实现应用程序的国际化,往往需要使用动态链接库。使用动态链接库可以将针对某一国家、语言的信息存放在其中。对于不同的版本,应使用不同的动态链接库。在使用AppWizard生成应用程序时,我们可以指定资源文件使用的语言,这就是通过提供不同的动态链接库实现的。(5) 拓展研发工具的功能。由于dll是和语言无关的,因此创建一个dll,能够被C+、VB或所有支持动态链接库的语言调用。如果一种语言存在不足,

12、就能通过访问另一种语言创建的dll来弥补。 23 VC+、C+ Builder、Delphi都可以编写dll文件。dll不是独立运行的程序,它是某个程序的一个部分,它只能由所属的程序调用,用户不能打开它。生成一个动态链接库时应包含两个文件:*.dll和*.lib。lib是编译时需要的,dll是运行时需要的。如果要完成源代码的编译,有lib就够了。如果要使动态链接的程序运行起来,有dll就够了。lib文件是必须在编译期就链接到应用程序中的,而dll文件是运行期才会被调用的。dll文件包含函数的实现,是可执行的代码。lib文件是dll的一个映像文件,一般包含一些索引信息,如dll导出的函数的名称和

13、位置等。动态链接库有两种调用方式:隐式调用和显示调用。 24 9.3.2 动态链接库调用动态链接库调用的方法分隐式和显式两种。1隐式调用应用程序使用lib文件链接到所需要使用的dll文件,库中的函数和数据并不复制到exe文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是dll中所要调用的函数的内存地址(lib文件是必需的),下面以动态链接库a为例说明其隐式调用步骤,可分为以下三步:(1) 确保a.dll和a.lib两个文件都存放到了指定目录(这里假设两个文件放在调用该库的应用程序所在目录); 25 (2) 将要调用函数(假设为test()函数)的文件定位信息(包含在lib文

14、件中)和声明写到调用该库及函数的代码头文件中。#pragma comment(lib,a.lib) /指定该动态链接库相应静态库的文件定位信息extern C_declspec(dllimport) test1); /对需调用的函数进行声明 (3) 进行(2)中的声明后,就可以在文件中调用该函数了。 26 2显式调用如果dll没有对应的.lib文件,那么就只能使用显示调用(动态加载)的方式了,显式调用步骤如下:(1) 创建一个函数指针,其指针数据类型要与调用的dll引出函数相吻合;(2) 通过Win32 API函数LoadLibrary()显式地调用dll,此函数返回dll的实例句柄;(3)

15、通过Win32 API函数GetProcAddress()获取要调用的dll的函数地址,把结果赋给自定义函数的指针类型;(4) 使用函数指针来调用dll函数; 27 (5) 调用完成后,通过Win32 API函数FreeLibrary()释放dll函数。同样,以动态链接库a的test函数为例,下面代码描述了显式调用过程。typedef int(*test)();/宏定义声明欲调用函数指针类型,/简要起见这里该函数没有形式参数 28 HINSTANCE hDll;/Dll句柄test myFun;/函数指针hDll=LoadLibrary(a.dll);/显式调用dll,a.dll文件放置在应用

16、程序所在目录if (hDll!=NULL) myFun=(test)GetProcAddress(hDll, test);/获取函数地址 29 if (addFun!=NULL)test();/函数调用FreeLibrary(hDll);/释放dll如前所述,dll正确调用的前提是,需将dll(隐式的还包括lib文件)放入系统可以找到的目录下(系统寻找dll文件的顺序依次为:应用程序所在目录当前目录Windows系统目录PATH环境中设置的其他目录),如果不能找到该dll库文件,则调用势必失败。 30 9.3.3 动态链接库编程dll可以简单分为两种类型,即用C/C+(不用对象)编写的基于AP

17、I的传统dll和基于MFC对象的dll。在VC中可以利用向导,以前者为例:在“FileNewProjects”中选择“Win32 Dynamic-Link Library”项,并在“Project Name”中输入“demo”之后,按“OK”按钮就可以生成一个dll工程。工程中的demo.ccp文件如下:#include stdafx.h#include demo.hBOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 31 switch (ul_reason_for_call)c

18、ase DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break; return TRUE; 32 / This is an example of an exported variableDEMO_API int nDemo=0;/ This is an example of an exported function.DEMO_API int fnDemo(void) return 42;void _declspec(dllexport) test() 33 Me

19、ssageBox(NULL,Its so easy!,test,MB_OK);/ This is the constructor of a class that has been exported. see demo.h for the class definitionCDemo:CDemo() return; 34 这就像C语言编写的应用程序一样,每一个dll必须有一个入口点,DllMain()是一个缺省的入口函数,用这个缺省的入口函数就能使动态链接库被调用时得到正确的初始化。参数中,hMoudle是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);

20、ul_reason_for_call是一个说明动态库被调原因的标志(当进程或线程装入或卸载动态链接库时,操作系统调用入口函数,并说明动态链接库被调用的原因);lpReserved为保留参数。 35 dll中定义了两种函数:导出函数(exportfunction(),可以被其他模块调用)和内部函数(internalfunction(),只能在dll内部使用)。该文件设计了一个名为nDemo()的导出变量,名为fnDemo()和text()的导出函数、一个名为Cdemo()的导出类,具体定义在demo.h中。_declspec(dllexport)是VC提供的一个关键字,用它可在动态链接库中输出一

21、个数据、一个函数或一个类,与_declspec(dllimport)配合使用(参见9.3.2节)。 36 WinSock是Windows平台下的网络编程接口,支持多种通信协议,这一点相信大家在本书的前些章节中已经深有体会。然而读者也许会产生疑问,WinSock是如何对不同通信协议进行选择呢?这主要是得益于基于链接库技术实现的SPI这种服务。通过SPI的运用,用户可以监控WinSock来调用、插入自己期望的操作,这对于网络通信、QoS(Quality of Service,质量服务)、数据包过滤、木马程序都是必要的。本节将对SPI服务编程进行介绍。9.4 传输服务提供者 37 9.4.1 SPI

22、介绍SPI是由WinSock2提供的建立在Windows开放系统架构WOSA(Windows Open System Architecture)之上的一种应用程序服务。这种架构允许第三方服务提供者插入进去,从而使得WinSock更加开放,也能够得到第三方的支持与扩展。1基本构成WinSock2 SPI由传输服务提供者和名字空间服务提供者组成。 38 传输提供者(Transport Providers,TP)一般称做协议堆栈,例如TCP/IP,能够提供建立通信、传输数据、日常数据流控制和错误控制等传输功能方面的服务。名字空间提供者(Name Space Providers,NSP)(如DNS名字

23、解析服务)把一个网络协议的地址属性和一个或多个用户友好名称关联到一起,以便启用与应用无关的名字解析方案。传输服务提供者是本书程序设计所关心的SPI服务,它可以分为两类:基础服务提供者(Base Service Provider,BSP)和分层服务提供者(Layered Service Provider,LSP)。 39 BSP执行网络传输基础协议(如TCP/IP)的具体细节,其中包括在网络上收发数据之类的核心网络协议功能,一般由开发商提供。LSP只负责执行高级的自定义通信功能,并依靠下面的基础服务提供者,在网络上进行真正的数据交换。LSP将自己安装到LSP链(参见9.4.2节)的基础服务提供者

24、上面,截取来自应用程序WinSock API的调用,安排适合的BSP来实现基础协议。如果把基础服务提供者比作“座位”,那么LSP就相当于“引座员”。只要程序环境支持WinSock2 SPI,程序员就可以通过定制、修改LSP,在基础协议上实现一些自定义的功能,如安全管理或带宽管理。 40 2SPI函数各种SPI都是Windows支持的dll,挂靠在WinSock2的WS2_32.dll模块下。SPI的实现基于SPI函数和SPI协议。SPI函数的类型可以通过其前缀加以区分,具体见表9-1。 41 表9-1 SPI函数前缀及含义 42 实际上,SPI函数就是WinSock具体动作的真正实现者,也就是

25、说,用户应用程序调用的WinSock2 API函数,基本都是由SPI提供给它们对应的运作方式而实现功能的,例如:API函数WSAConnect有相应的SPI函数WSPConnect,调用WSAConnect,WSAConnect又调用WSPConnect来实现具体的动作。被应用程序调用的WS2_32.dll里的WinSock API函数,大部分都最终映射成了SPI里的30个函数,这30个函数都是用WSP开头的。 43 不被映射到SPI的WinSock API操作主要有以下几种情况:(1) 地址转换函数,如hton()、lhtons()、ntohl()、ntohs()、inet_addr()、i

26、net_ntoa()。(2) WinSock错误码查询函数,如WSAGetlastErro()、WSASetlastError()。(3) 事件对象操作和等待函数,如WSACreateEvent()、WSASetEvent()、WSARetEvent()、WSACloseEvent()、WSAWaitforMutipleEvents()。(4) WinSock服务提供者枚举函数,如WSAEnumProtocals()。 44 (5) 名字转换和地址解析函数,如gethostname()等。SPI里的函数是不能被应用程序直接调用的,而是应该由WS2_32.dll来调用。 45 3协议分类Wind

27、ows Socket SPI提供了三种协议:分层协议、基础协议和协议链。分层协议是在基础协议的上层,依靠底层基础协议实现更高级的通信服务。基础协议是能够独立、安全地和远程端点实现数据通信的协议,它是相对于分层协议而言的。协议链是将一系列的基础协议和分层协议按特点的顺序连接在一起的链状结构。 46 4工作位置SPI处于WS_32.dll和底层的通信协议之间,文件位置如图9-4所示,协议位置如图9-5所示。SPI向上为用户应用程序提供一个标准的API接口,向下为WinSock组件和WinSock服务提供者(比如TCP/IP协议栈)之间提供一个标准的SPI接口。 47 图9-4 SPI文件位置 48

28、 图9-5 SPI协议位置 49 5动态加载调用WSAStartup期间,WinSock根据WSASocket调用的地址家族、套接字类型和协议参数,以决定需要加载哪个服务提供者。以TCP/IP协议为例,只有在一个应用程序通过Socket或WSASocket API调用建立一个地址家族为AF_INET、套接字类型为SOCK_STREAM的套接字时,WinSock才会搜索并加载与之相应的、能够提供TCP/IP能力的传输服务提供者。WSPStartup的参数UpcallTable取得WS2_32.dll的SPI函数派遣表,LSP利用这些函数来管理自身和WinSock2之间的I/O操作。 50 9.4

29、.2 LSP编程本节重点介绍LSP编程的主要思想。1开发原则TSP的BSP实现了网络协议传输的实际细节,包括建立连接、传送数据、流控制和差错控制。各种协议就是在BSP中实现的。一般的BSP是由操作系统厂商和传输协议栈厂商提供的。即使用户开发了自己的BSP,也会因为无法推广而变得毫无意义。另外,NSP与TSP类似,理论上也可以分为基础的和分层的SP,但是目前分层的服务系统还不支持,而基础的也由开发商提供,由此可见留给程序员的传输者服务编程主要就是LSP的开发。 51 LSP是BSP之上的,用于实现高层的用户自定义的通信功能,具体包括:监控和过滤网络数据、修改网络数据(包括加密)、数据重定向、UR

30、L重定向(代理服务器)、防火墙、WOSA实现等功能。由于LSP依赖于下层的BSP,因此这种自定义的通信功能设计要受到BSP功能的限制,比如开发者可以在此基础上开发许多有用的应用。 52 2程序结构WinSock2 LSP都是标准的Windows dll,这些dll只有一个导入的入口函数,即WSPStartup。该SPI函数的原型如下:int WSPStartup ( WORD wVersionRequested, /调用者支持的最高版本号 LPWSPDATAW lpWSPData, /用于接收WinSock的SP的信息指针 53 LPWSAPROTOCOL_INFOW lpProtocolIn

31、fo, /用于定义期望协议特征的/WSAPROTOCOL_INFO指针 WSPUPCALLTABLE UpcallTable, /WS2_32.dll的呼叫派遣表 LPWSPPROC_TABLE lpProcTable /指向SPI函数指针表的指针); 54 参数lpProcTable是一个LPWSPPROC_TABLE结构体,这个结构体定义了一个LSP必须实现的函数,以及这些函数的入口点。LPWSPPROC_TABLE的结构如下:typedef struct _WSPPROC_TABLE LPWSPACCEPT lpWSPAccept; LPWSPADDRESSTOSTRING lpWSPA

32、ddressToString; LPWSPASYNCSELECT lpWSPAsyncSelect; 55 LPWSPBIND lpWSPBind; LPWSPCANCELBLOCKINGCALL lpWSPCancelBlockingCall; LPWSPCLEANUP lpWSPCleanup; LPWSPCLOSESOCKET lpWSPCloseSocket; LPWSPCONNECT lpWSPConnect; 56 LPWSPDUPLICATESOCKET lpWSPDuplicateSocket; LPWSPENUMNETWORKEVENTS lpWSPEnumNetworkEv

33、ents; LPWSPEVENTSELECT lpWSPEventSelect; LPWSPGETOVERLAPPEDRESULT lpWSPGetOverlappedResult; 57 LPWSPGETPEERNAME lpWSPGetPeerName; LPWSPGETSOCKNAME lpWSPGetSockName; LPWSPGETSOCKOPT lpWSPGetSockOpt; LPWSPGETQOSBYNAME lpWSPGetQOSByName; 58 LPWSPIOCTL lpWSPIoctl; LPWSPJOINLEAF lpWSPJoinLeaf; LPWSPLISTE

34、N lpWSPListen; LPWSPRECV lpWSPRecv; LPWSPRECVDISCONNECT lpWSPRecvDisconnect; 59 LPWSPRECVFROM lpWSPRecvFrom; LPWSPSELECT lpWSPSelect; LPWSPSEND lpWSPSend; LPWSPSENDDISCONNECT lpWSPSendDisconnect; LPWSPSENDTO lpWSPSendTo; 60 LPWSPSETSOCKOPT lpWSPSetSockOpt; LPWSPSHUTDOWN lpWSPShutdown; LPWSPSOCKET lp

35、WSPSocket; LPWSPSTRINGTOADDRESS lpWSPStringToAddress; WSPPROC_TABLE, FAR * LPWSPPROC_TABLE; 61 可以看出这个结构非常复杂。通常,我们只需要设计所关心的少量函数,对于没有涉及的函数,可以让其直接调用下一个LSP相应的函数(当然,用户在插入一个自己设计的LSP之前,系统就已经有其他的LSP存在了)。 62 3LSP链LSP和BSP被串了起来,形成一个协议链。WSAPROTOCOL_INFOW结构体(与结构体WSAPROTOCOL_INFO一致,见5.2.1节)就是整个的协议链,它描述了LSP、SPI的连接

36、顺序(如图9-5所示),可以使用PSDK提供的工具对计算机上的LSP链进行查询(参见9.4.3节)。在WS2_32.dll调用LSP时就是按照LSP链来顺序加载的。首先LSP链最顶端的LSP由WS2_32.dll加载,其余的LSP由上一层LSP加载。 63 无论由谁加载一个LSP,加载LSP后,会调用它的SPI函数WSPStartup(),并通过函数的UpcallTable参数(WSPUPCALLTABLE结构体)把上层的LSP信息传给下层。如果一个LSP的下一层是LSP而不是BSP,则代表协议链信息的lpProtocolInfo (LPWSPPROC_TABLE)也会被SPI函数WSPSta

37、rtup传递给下层的LSP。程序中,WSPStartup可能被调用多次,每调用一次都必须调用一次SPI函数WSPCleanup(),以保证内存不被浪费。 64 4LSP安装1) 安装原理LSP安装程序通过配置WinSock2系统配置数据库(WinSock2 system configuration database)实现LSP的安装。这个数据库实际上就是所有已安装的service providers的目录。WinSock2可以通过这个数据库知道service provider的存在及其定义所提供服务的类型。当WinSock应用程序创建socket时,WinSock2就会用这个数据库来确定所需加

38、载的TSP。 65 具体是由WS2_32.dll 搜索数据库以找到与该Socket或WSASocket API调用的输入参数(如地址族、socket 类型和协议)相匹配的第一个provider(当存在多个相匹配时,使用第一个)。进而WS2_32.dll就加载目录中指定的相应的service provider dll。这就解释了同样的WinSock函数可以使用不同的通信协议的问题(参见5.2.1节)。 66 2) 安装方法要成功安装并管理WinSock2系统配置数据库中的服务提供者实体(service provider entry)需要四个函数。这四个函数均都是以WSC为前缀开头,它们分别是WS

39、CEnumProtocols()、WSCInstallProvider()、WSCWriteProviderOrder()、WSCDeinstallProvider()。归纳起来,在安装过程中,这几个函数主要关心的是ProviderId、dwCatalogEntryId和ProtocolChain这三个域。ProviderId域是一个全局唯一的标识符,该标识符可用来在任何系统上定义和安装provider。 67 dwCatalogEntryId域只是标识了数据库中的每一个WSAPROTOCOL_INFOW目录项结构体。ProtocolChain决定了每个WSAPROTOCOL_INFOW 结构

40、体的类型,结构原型如下:typedef struct int ChainLen; /链值DWORD ChainEntriesMAX_PROTOCOL_CHAIN; /目录ID数组 WSAPROTOCOLCHAIN, FAR * LPWSAPROTOCOLCHAIN; 68 参数ChainLen 决定了目录项表示BSP、LSP或是定义一个协议链(length的值为0时代表LSP,为1代表BSP,大于1时表示这是一个协议链)。对于LSP和BSP,在数据库中每个开发商(provider)只有一个目录项。最后的ChainEntries域表示的目录IDs是用来描述协议链目录项中SP的加载顺序的。安装LS

41、P时,需要创建两个WSAPROTOCOL_INFOW目录项结构体,一个表示LSP,另一个表示将LSP链接到BSP的协议链。使用前要进行初始化,在初始化之后调用WSCInstallProvider()函数来安装LSP的目录项,继而再取得初始化后赋给此结构体的目录 ID。这样目录项就可以建立将LSP链接到另一个provider(可以是LSP,也可以是BSP)的协议链目录项。 69 安装链接的provider还要调用WSCInstallProvider()函数,其中LSP的WSAPROTOCOL_INFOW结构体中指定了PFL_HIDDEN 标志,保证了WSAEnumProtocols (参见5.2

42、.1节)不会在返回的缓冲区中包含LSP的目录。 70 3) 位置排序完成上面步骤之后,LSP就安装到系统上了。但是工作并没有全部完成,想要这个新安装的LSP被正确调用,还需对其位置进行正确排序。这是因为WinSock2在数据库中查找SP时,要通过socket或WSASocket的调用参数来确定打算使用的协议,会首先使用在目录最上头的匹配项。例如,如果创建使用AF_INET地址族和SOCK_STREAM类型的socket,WinSock2会首先在提供此功能的数据库中查找目录最上面的可用的TCP/IP协议链目录项或是BSP目录项。 71 而上面用WSCInstallProvider为LSP安装协议

43、链时,目录项会自动变为数据库的最后一项。为了让新的链成为默认的TCP/IP提供者,还必须将数据库重新排序并调用,即调用WSCWriteProviderOrder将协议链目录项放在其他同类的TCP/IP SP的前面。位置排序完成后,LSP的安装才算全部完成。 72 9.4.3 LSP程序设计由9.4.2节已知LSP编程需要完成两个部分,即安装和实现.dll文件。安装文件将实现文件安装到WinSock2系统配置数据库中,用户就可以调用实现文件进行具体的操作了。1安装程序下面对LSP的安装程序进行介绍。在微软提供的PSDK中(以Microsoft Platform SDK for Windows S

44、erver 2003 R2为例)就有包含LSP的安装文件(在路径.Microsoft Platform SDK for Windows Server 2003 R2SamplesNetDS 73 WinSockLSPinstall文件夹下),其主要实现在instlsp.cpp文件里,下面对该文件的主要功能函数及其代码功能进行分析介绍。/主要功能函数:BOOLgetfilter(); /获得所有已经安装的传输服务 void freefilter(); /释放存储空间 void installfilter(); /安装分层协议、协议链及排序void removefilter(); /卸载分层协议和

45、协议链/函数代码分析: 74 protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc (GPTR,protoinfosize); /分配WSAPROTOCOL_INFOW结构的存储空间 totalprotos=WSCEnumProtocols(NULL,protoinfo, 75 /构造服务提供者文件ipfilter.dll的路径全名 WSCInstallProvider( /获得已安装的自定义IP分层协议的由WS2_32.dll分配的唯一标志udpchaininfo.ProtocolChain.ChainEntries0=iplayercataid; /将自定义

46、的IP分层协议作为自定义UDP协议链的根分层服务提供者,安装在协议链的顶端 76 WSCInstallProvider( /获得调用本服务提供者动态链接库的可执行文件的全名 OutputDebugString(_T(WSPSendTo Tencent Filtered); /输出调试信息 nextproctable.lpWSPSendTo(s,lpbuffer, dwbuffercount,lpnumberofbytessent,dwflags,lpto, 85 itolen,lpoverlapped,lpcompletionroutine, lpthreadid,lperrno); /如果数

47、据报满足发送条件,则调用下层系统服务提供者发送数据 layerid=protoinfoi.dwCatalogEntryId; /获得已安装的自定义IP分层协议的由WS2_32.dll分配的唯一标志 nextlayerid=lpprotoinfo-ProtocolChain.ChainEntriesi+1; /获得下一层传输服务提供者的标志信息 86 WSCGetProviderPath( /保存下一层服务提供者的30个服务函数指针 lpproctable-lpWSPSendTo=WSPSendTo; /调用自定义函数WSPSendTo 由于动态链接库形式的服务提供者要向外提供一个入口函数,因此

48、还需一个配置文件ipfilter.def: EXPORTS WSPStartup /向外提供入口函数WSPStartup 89 利用本程序的设计方法,还可以实现对高级应用程序的控制,如通过对80端口的监控来禁用Http协议,屏蔽UDP数据包通过,计算流经的数据包个数来统计流量等,防火墙监控器的功能。需说明的是,这种基于SPI的编程方法工作在用户模式下,对于一些直接调用TDI的程序不起作用。 90 本章介绍了链接库这种代码集成技术和基于链接库技术的SPI编程技术,为程序员进行代码复用、软件的升级、调用的标准化、不同编程器协同编程、提高程序效率提供了良好的手段。对于基于链接库技术实现的WinSock2 SPI服务技术的掌握虽然难度很大,但是它允许用户在现有WinSock的功能中插入更多的监管、控制网络通信的功能,从而开辟了更大的网络编程发挥的空间,对于网络管理、网络安全都有重要意义。小 结

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!