网络编程实用教程_第4章.ppt_第1页
网络编程实用教程_第4章.ppt_第2页
网络编程实用教程_第4章.ppt_第3页
网络编程实用教程_第4章.ppt_第4页
网络编程实用教程_第4章.ppt_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第4章 WinInet编程,WinInet是Windows Internet扩展应用程序高级编程接口,是专为开发具有Internet功能的客户端应用程序而提供的。 WinInet有两种形式: WinInet API包含一个C语言的函数集(Win32 Internet functions); MFC WinInet类层次则是对前者的面向对象的封装。 WinInet支持FTP、HTTP、Gopher协议。 使用WinInet可以使客户端应用程序轻松地与这三种服务器通信,而无需考虑底层通信细节。,4.1 使用WinInet API的共性问题,使用WinInet API,应用程序可以与Internet

2、服务器建立连接、查询或接收服务器文件、向服务器发送文件、打开服务器上的文件,等等。 进行操作时可以使用同步方式或异步方式。 WinInet API的函数原型定义在Wininet.h头文件中,对应的函数实现在Wininet.lib库文件中。 要想成功地编译使用WinInet API的应用程序, 正在使用的C/C+的include目录中必须有Wininet.h头文件,library目录中必须有Wininet.lib库文件。,4.1.1 WinInet API函数使用的HINTERNET句柄 HINTERNET句柄是一种特殊的数据类型,由少数WinInet API函数创建,大多数WinInet AP

3、I函数通过使用HINTERNET类型的句柄来实现函数的操作。 HINTERNET句柄可以代表Internet会话,也可以代表应用程序与Internet上特定服务器的连接,还可以代表各种打开的文件或查询结果。 HINTERNET句柄与普通的Win32句柄相似。 区别在于处于不同层次的HINTERNET句柄形成了一个树形体系,且只有少数函数能够创建HINTERNET句柄。,图4.1 各种HINTERNET句柄形成的树形体系结构,各种HINTERNET句柄都有相应的数据结构,记录句柄的属性信息,并提供通过该句柄可以实现的操作。 下层句柄是由上层句柄派生出来的,下层句柄继承上层句柄的属性。 当用户调用

4、InternetCloseHandle函数来关闭一个句柄时,由该句柄派生的所有下层句柄都将被关闭。 HINTERNET句柄有许多选项,这些选项决定了句柄的行为和属性,如句柄的操作方式、超时设置、异步操作时的回调函数、环境上下文ID、缓冲区大小等。 句柄的类型不同,选项也不同。应用程序可以调用InternetQueryOption函数来查询句柄的选项设置,调用InternetSetOption函数来改变句柄的选项设置。,图4.2 依赖由InternetOpenUrl所创建句柄的三个函数,4.1.2 典型的操作流程和它们使用的句柄 1. 使用InternetOpenUrl直接打开因特网上指定的文件

5、,2FTP操作的层级结构 (1) 对FTP服务器的目录和文件进行操作,图4.3 对FTP服务器的目录和文件进行操作的流程,(2) 使用内存缓冲区来操作FTP服务器上的文件.,图4.4 使用内存缓冲区来操作FTP服务器上的文件,(3) 查询FTP服务器上的文件,图4.5 查询FTP服务器上的文件,4.1.3 如何获取WinInet API函数执行的错误信息 从函数的返回值来说,WinInet API主要有两种类型。 一种函数的返回值类型是HINTERNET句柄型; 一种函数的返回值类型是布尔型。 应用程序可以根据函数执行后的返回值来判断函数的执行是否成功。 对于前一种函数,当函数执行成功时,返回

6、一个有效的句柄;当函数失败时,则返回NULL。 对于后一种函数,当函数执行成功时,返回TRUE;当函数失败时,返回FALSE。 在函数调用失败后,用户往往需要了解出错的具体原因,应用程序可以随即调用GetLastError函数来获取更具体的错误信息。,4.1.4 关于返回信息的缓冲区参数 许多WinInet API函数使用两个参数来向应用程序返回信息。 lpszBuffer是指向数据缓冲区的指针(LPVOID lpszBuffer),可以为NULL。 lpdwBufferLength是指向缓冲区长度的指针(LPDWORD lpdwBufferLength),它在函数开始执行时指示缓冲区的大小,

7、不能为NULL。,函数执行完毕时,作为函数的出口参数,返回一个长度可变的信息。 若调用成功 lpszBuffer指向的缓冲区中存储着返回的信息内容。 lpdwBufferLength所指的双字就被设置为实际存入缓冲区的数据的字节长度。 若lpszBuffer指针为NULL,或lpdwBufferLength指示的缓冲区大小不足以容纳返回的数据,函数调用将失败,并在函数返回时将lpdwBufferLength所指的值设置为接受返回数据所需的缓冲区字节数。 用户可以使用这个返回值,重新分配一个更大的缓冲区,并重新调用函数。,4.1.5 WinInet API的异步操作模式 WinInet API的

8、函数在进行I/O操作时,默认的方式是同步操作,即对于每一个不能及时完成的I/O操作,会一直等下去,直到操作完成。 异步操作,无论成功与否函数调用都会立即返回,这样就允许一个单线程的应用程序最充分地利用CPU,而不必等待网络I/O的完成。 当调用异步操作模式的函数时,应检查返回值。 若函数调用返回FALSE或NULL,并且调用GetLastError返回一个ERROR_IO_PENDING错误,说明该函数调用已经异步的完成了。 并且当函数执行完毕时,会使用INTERNET_STATUS_REQUEST_COMPLETE状态码来自动的调用应用程序的回调函数。,为了使WinInet以异步方式操作,应

9、用程序需要做四件事。 设置异步方式标志 在调用InternetOpen函数来创建Inernet根句柄时,将参数dwFlags设置为INTERNET_FLAG_ASYNC异步标志。 这表示接下来针对根句柄及其派生句柄的操作都以异步方式进行。 任何调用在异步结束后均返回一个对话句柄或由此而派生的句柄。,设置非零的环境值 WinInet中创建句柄的函数都有一个称为环境值的入口参数,名字总是dwContext。 如果要求针对某个句柄的函数以异步的方式来操作,在调用创建该句柄的函数时,对dwContext参数必须指定一个非零的环境值。 如果把环境值指定为0,即使在上一步操作中设置了INTERNET_FL

10、AG_ASYNC标志,依赖该句柄的函数也只能以同步方式来操作。,定义并实现一个状态回调函数(status callback function) 对于长时间操作的WinInet函数,回调函数可以给应用程序返回一些关于操作进展情况的反馈,并主要是与网络操作有关的情况。 eg:解析了一个域名、正在连接服务器、正在接收数据 异步操作完成时将调用回调函数,给出某种指示. INTERNET_STATUS_HANDLE_CLOSING是对于一个句柄最后做的状态指示; INTERNET_STATUS_HANDLE_CREATED是当句柄初始创建时的指示; INTERNET_STATUS_REQUEST_COM

11、PLETE是当一个异步操作完成时的指示。 当接收到一个INTERNET_STATUS_REQUEST_COMPLETE指示时,应用程序必须检查INTERNET_ASYNC_RESULT结构,来决定操作是成功还是失败。,为句柄注册有效的回调函数 通过调用InternetSetStatusCallback函数可以建立一个回调函数与一个句柄的关联,称为注册。 一旦建立了这种关联,所有对于这个句柄的异步操作就都调用这个回调函数,产生状态指示,汇报函数的操作情况。 回调函数被该句柄派生的句柄继承,对于其派生句柄的异步操作也都将调用这个回调函数。 使用InternetSetStatusCallback函数

12、也可以改变一个句柄关联的回调函数,但是改变了一个句柄关联的回调函数并不改变其派生句柄的关联回调函数. 异步操作在调用回调函数时,会将所操作的句柄创建时指定的非零环境值,以及对这个句柄操作的状态指示等信息,作为入口参数传递给回调函数,利用传入的环境值,可以核查向回调函数产生调用的操作,从而判别出这此回调是哪个异步操作引起的,进而做出不同的处理。,4.1.6 回调函数的定义实现与注册 1回调函数的原型 VOID (CALLBACK * INTERNET_STATUS_CALLBACK)( IN HINTERNET hInternet, IN DWORD dwContext, IN DWORD dw

13、InternetStatus, IN LPVOID lpvStatusInformation, IN DWORD dwStatusInformationLength );,2INTERNET_ASYNC_RESULT结构的定义 此结构包含异步回调函数的结果。 typedef struct DWORD dwResult; DWORD dwError; INTERNET_ASYNC_RESULT, * LPINTERNET_ASYNC_RESULT;,3注册句柄的回调函数 调用InternetSetStatusCallback函数可以建立回调函数与句柄的关联。 INTERNET_STATUS_CA

14、LLBACK InternetSetStatusCallback( IN HINTERNET hInternet, IN INTERNET_STATUS_CALLBACK lpfnInternetCallback );,4举例 下面给出了一个回调函数的例子,和一个调用InternetSetStatusCallback来注册回调函数的例子. /定义了一个回调函数,函数名是用户自己定义的。 void CALLBACK CInternet:InternetCallback( HINTERNET hInternet, / 其它参数原样照抄 DWORD dwcontext, DWORD dwIntern

15、etStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength ) / 在这里插入回调函数的实现代码。. ; /定义INTERNET_STATUS_CALLBACK型的变量 INTERNET_STATUS_CALLBACK dwISC; / 建立句柄与回调函数的关联 dwISC = InternetSetStatusCallback(hInternet, (INTERNET_STATUS_CALLBACK) InternetCallback);,4.2 使用WinInet API编制FTP客户程序的要点,4.2.1

16、一般步骤 FTP客户端应用程序的一般步骤是: 调用InternetAttemptConnect函数测试主机与Internet的连接状态; 调用InternetOpen函数,创建HINTERNET会话根句柄; 创建FTP会话句柄,调用函数时需要服务器名、FTP端口号、用户名和口令,设置INTERNET_SERVICE_FTP标志,若将端口号设置为HINTERNT_INVALID_PORT_NUMBER,则使用默认端口号; 对于FTP服务器执行需要的操作:,对于FTP服务器执行需要的操作: 搜寻并列举FTP服务器上的文件和目录 使用FtpFindFirstFile和InternetFindNext

17、File函数。 查知或改变FTP服务器的当前目录 使用FtpGetCurrentDirectory和FtpSetCurrentDirectory函数。 操作服务器上的目录 使用FtpCreateDirectory和FtpRemoveDirectory函数. 下载FTP服务器中的文件 使用FtpOpenFile和InternetReadFile函数 下载和上传文件 使用FtpGetFile和FtpPutFile函数。,4.2.2 搜寻并列举FTP服务器上的文件和目录 使用FTP的主要目的是操作文件,经常要在FTP服务器上查找符合一定条件的目录或文件,称为目录列举. 符合条件的对象可能有很多,需要

18、使用两个WinInet函数才能把所有的都搜索出来。 首先,调用FtpFindFirstFile函数,找到服务器上第一个匹配的文件或目录,并返回一个HINTERNET句柄。 在此基础上,可以使用这个句柄,反复调用InternetFindNextFile函数,搜寻到其它的匹配文件或目录,直到返回ERROR_NO_MORE_FILES时,说明所有匹配的对象都找到了。,FtpFindFirstFile函数的原型: HINTERNET FtpFindFirstFile( IN HINTERNET hFtpSession, / 指定FTP会话句柄 IN LPCSTR lpszSearchFile, / 指

19、定要寻找的目录或文件路径 OUT LPWIN32_FIND_DATA lpFindFileData, / 返回的搜寻结果 IN DWORD dwFlags, / 设置影响函数执行的标志 IN DWORD dwContext / 环境值 ); 如果函数执行成功,返回一个有效的句柄,用于InternetFindNextFile,继续查询,否则返回NULL。 如果函数找不到匹配对象,则调用GetLastError函数返回一个ERROR_NO_MORE_FILES错误。,在一个FTP会话期内,只可以调用一次FtpFind FirstFile函数,此后应使用InternetFindNextFile函数列

20、举出其余符合条件的目录和文件。 并将结果返回到WIN32_FIND_DATA结构中。 InternetFindNextFile函数比较简单,其原型是: BOOL InternetFindNextFile( IN HINTERNET hFind, / 查找句柄 OUT LPVOID lpvFindData); / 查找的结果 函数返回值是BOOL型,如果执行成功返回TRUE,否则返回NULL。 如果函数找不到匹配对象,则调用GetLastError函数返回一个ERROR_NO_MORE_FILES错误。,4.2.3 查知或改变FTP服务器的当前目录 应用程序对于FTP服务器上的当前目录的控制称为

21、目录导航。 调用FtpGetCurrentDiretory函数能够查知FTP服务器上的当前目录是哪一个; 调用FtpSetCurrentDiretory函数能够将FTP服务器上的当前目录改变到指定目录。,FtpGetCurrentDiretory函数的原型: BOOL FtpGetCurrentDirectory( IN HINTERNET hFtpSession, / FTP会话句柄 OUT LPSTR lpszCurrentDirectory, / 返回当前目录的缓冲区指针 IN OUT LPDWORD lpdwCurrentDirectory / 缓冲区的字符长度。 ); FtpSetC

22、urrentDirectory函数的原型: BOOL FtpSetCurrentDirectory( IN HINTERNET hFtpSession, / 有效的FTP会话句柄 IN LPCSTR lpszDirectory / 要设置的新当前目录路径 ); 返回值是BOOL型的,成功返回TRUE,失败返回FALSE.,4.2.4 操作服务器上的目录 使用WinInet API函数可以在FTP服务器上创建和删除目录,当然应用程序应当具有相应的权限。 在调用InternetConnect时,指定具有相应权限的用户名和口令,正确地登录到FTP服务器。 调用FtpCreateDirectory可以

23、在FTP服务器上创建新的目录,函数原型是: BOOL FtpCreateDirectory( IN HINTERNET hFtpSession, /有效的FTP会话句柄 IN LPCSTR lpszDirectory /字符串指针,用于指定要创建的目录路径(名) );,调用FtpRemoveDirectory可以删除FTP服务器上的指定的目录,函数原型是: BOOL FtpRemoveDirectory( IN HINTERNET hFtpSession, /有效的FTP会话句柄 IN LPCSTR lpszDirectory /字符串指针,用于指定要删除的目录路径(名) ); 以上两函数的返

24、回值是BOOL型,调用成功,返回TRUE,否则返回FALSE。 应用程序可以使用FtpGetCurrentDirectory函数来决定远方FTP站点的当前工作目录。,FtpCreateDirectory函数的原型是 BOOL FtpCreateDirectory( IN HINTERNET hFtpSession, / 有效的FTP会话句柄. IN LPCSTR lpszDirectory / 要创建的目录路径. ); FtpRemoveDirectory函数的原型是 BOOL FtpRemoveDirectory( IN HINTERNET hFtpSession, / 有效的FTP会话句柄

25、. IN LPCSTR lpszDirectory / 要删除的目录路径. );,31,4.2.5 下载FTP服务器中的文件 WinInet为客户端应用程序提供了三种从FTP服务器上获取文件的方法。 (1)使用InternetOpenURL和InternetReadFile函数 如果用户确切的知道文件有效的URL,并且应用程序想要更紧密的控制下载的过程,同时在FTP服务器上不需要进行其它的操作,可以使用这种方法。 应用程序直接调用InternetOpenURL函数打开由RUL指定的服务器文件,创建文件句柄,再调用InternetReadFile函数下载文件的内容,这种方法允许应用程序对下载有更

26、强的控制,是通用的下载方法。,(2)使用FtpOpenFile和InternetReadFile函数 如果应用程序已经调用InternetConnect函数创建了一个到服务器的FTP会话句柄,可以首先调用FtpOpenFile函数打开服务器上的现存文件,再调用InternetReadFile来下载文件,并保持与FTP服务器的连接,因此允许执行更多的其他命令。 在如下两种情况应使用这种下载方法: 应用程序需要从服务器获得一个文件,并把文件信息首先装入应用程序控制的内存缓冲区,而不是直接写到磁盘的一个文件中; 应用程序需要对文件的传送过程进行很好的控制,如下载过程中显示进度指示器。,FtpOpen

27、File函数原型是: HINTERNET FtpOpenFile( IN HINTERNET hFtpSession, / Ftp会话句柄. IN LPCSTR lpszFileName, / 字符串指针,指向要访问的远程文件名 IN DWORD fdwAccess, /对文件做的操作,只读或写 IN DWORD dwFlags, /传送方法与缓存方法. IN DWORD dwContext, /环境值. ); 函数返回HINTERNET句柄,初始化对远地文件的访问,如果成功返回一个句柄,供InternetReadFile或InternetWriteFile使用,如果失败返回NULL。,在使用

28、FtpOpenFile函数打开了FTP服务器上的一个文件,并成功地返回了一个文件句柄之后,应用程序必须使用InternetReadFile函数下载文件的内容。 InternetReadFile函数的原型是: BOOL InternetReadFile( IN HINTERNET hFile, / FtpOpenFile返回的文件句柄. IN LPCVOID lpBuffer, / 接收数据的内存缓冲区指针. IN DWORD dwNumberOfByetesToWrite, /要读的字节数. OUT LPDWORD lpdwNumberOfByetesWriten , /实际读到的字节数. )

29、; 函数成功执行返回TRUE,否则返回FALSE。 如果返回值是TRUE,并且读到的字节数是0,说明传送已经完成,可调用InternetCloseHandle释放连接。,lpBuffer缓冲区应足够大,下载一个服务器文件往往要多次调用InternetReadFile函数,直到把数据都读完。 每次调用时,函数会尽量多读数据,如果网络上的数据尚未到达,函数会等待,直到读够数据。 在一个FTP会话中,仅仅可以打开一个文件,只能同时存在一个文件句柄。 如果在未调用InternetCloseHandle关闭前面的文件句柄时,就继续调用FtpOpenFile,会产生ERROR_FTP_TRANSFER_I

30、N_PROGRESS错误。,(3)使用FtpGetFile函数。 如果应用程序并不需要紧密地控制下载,可以使用FtpGetFile函数,直接指定服务器上的远程文件名和下载后在本地存储的文件名,来获得文件。 函数同样要求已经用InternetConnect建立了到服务器的FTP会话连接。,应用程序可以调用FtpGetFile函数将远程文件存为本地系统中的文件,此函数将文件从远程FTP服务器中读出,并以指定的文件名存在本地系统中。 FtpGetFile函数的原型是: BOOL FtpGetFile( IN HINTERNET hFtpSession, / Ftp会话句柄. IN LPCSTR lp

31、szRemoteFile, / 服务器上的远程文件名 IN LPCSTR lpszNewFile, / 存在本地的文件名. IN BOOL fFailIfExists, /如何处理同名文件. IN DWORD dwLocalFlagsAndAttributes, /新创建的文件的属性. IN DWORD dwInternetFlags, /传送方法与缓存方法. IN DWORD dwContext, /环境值. ); 函数成功执行返回TRUE,否则返回FALSE。,4.2.6 上传文件 上传文件是指在FTP服务器上放置一个文件。 在WinInet中有两种方法。 (1)使用FtpOpenFile

32、和InternetWriteFile 如果应用程序要发送一些数据到FTP服务器,并且要把这些数据作为一个文件存在服务器上,而应用程序并没有一个本地文件包含这些数据,数据在内存缓冲区内,可以使用FtpOpenFile以写的方式打开文件,创建文件句柄,然后再调用InternetWriteFile将数据发送到服务器的文件中。 (2)使用FtpPutFile 如果本地文件已经存在,应用程序可以紧密地控制文件的传送。,(1)使用FtpOpenFile和InternetWriteFile FtpOpenFile的用法与下载文件基本相同,区别在于必须以写的方式打开。 然后调用InternetWriteFile将本地内存

温馨提示

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

评论

0/150

提交评论