Winsock程序综合实例.ppt_第1页
Winsock程序综合实例.ppt_第2页
Winsock程序综合实例.ppt_第3页
Winsock程序综合实例.ppt_第4页
Winsock程序综合实例.ppt_第5页
已阅读5页,还剩73页未读 继续免费阅读

下载本文档

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

文档简介

第1页,人民邮电出版社,第10章 Winsock程序综合实例,第2页,10.1 使用MFC类库设计网络程序,10.1.1 MFC类库简介 MFC(Microsoft Foundation Classes)是微软公司提供的用于C+程序设计的基础类库,它由两大部分组成:一部分是通常所说的C+类库,是MFC类库的主体部分,这些类构成了MFC应用程序框架;另一部分是MFC预定义宏、全局变量和全局函数,是MFC类库的辅助部分。这两部分都是用MFC进行Windows应用程序开发不可缺少的组成部分。,第3页,10.1 使用MFC类库设计网络程序,MFC类库中定义的类主要有以下几种: (1)根类 根类指CObject类,它是大多数MFC类的最终基类,其他类都继承了CObject类的三个主要特征: 在运行时识别对象所属的类。 支持串行化,把对象存入文件中及从文件中读取对象。 在运行时打印诊断信息。,第4页,10.1 使用MFC类库设计网络程序,(2)命令发送类 命令发送类CCmdTarget封装了用户通过选择菜单或工具栏按钮向应用程序发送命令的界面。命令发送类CCmdTarget派生自CObject根类,它是应用程序结构类和窗口类的基类。,第5页,10.1 使用MFC类库设计网络程序,(3)应用程序结构类 应用程序结构类(Application Architecture Class)提供了应用程序的几乎所有通用功能,它们构成了Windows应用程序的主要框架。我们通过这些类的派生类,添加新成员函数或重载现有成员函数以实现需要的功能,从而构造应用程序框架。应用程序类主要有: 应用程序线程支持类:MFC支持多线程,所有的应用程序至少有一个线程。CWinThread类是所有线程类的基类,封装了操作应用程序的多线程功能。CWinApp是CWinThread类的派生类,它封装了基于MFC的Windows应用程序的初始化、运行及终止等功能。CWinApp的全局对象控制着整个应用程序的流程。,第6页,10.1 使用MFC类库设计网络程序,文档类:文档类封装了应用程序的数据管理,文档类对象由文档模板创建。CDocument 类是文档类的基类,用户应用程序文档类可从CDocument类直接派生。CDocument类支持一些标准操作,如新建文档,打开文档和存储文档等。 文档模板类:文档模板类将文档、视图及边框窗口相互联系起来,在创建新文档或视图时协调文档、视图及边框窗口的创建。CDocTemplate类是一个抽象基类,它为文档模板封装了基本功能,用户不能直接使用该类。CMultiDocTemplate为多文档接口(MDI)提供了模板。CSingleDocTemplate为单文档接口(SDI)提供模板。,第7页,10.1 使用MFC类库设计网络程序,(4)窗口类 窗口类包括边框窗口类、视图类、对话框类、控件类、控件栏类和属性簿类,这些类的共同之处是都封装了一个窗口句柄HWND,都是从CWnd派生的。 (5)常用工具类 在MFC中还定义了大量的工具类,如用于绘图的类、数组类等。 (6)非派生自CObject的类 在MFC中有些类不是从CObject类派生的,如用于Internet服务程序设计的API(Internet Server API)等。,第8页,10.1 使用MFC类库设计网络程序,10.1.2 MFC中与网络程序设计有关的类 在MFC类库中,与网络程序设计有关的类有以下几种: (1)文件服务类(File Services) 在有关文件服务类的定义中有一个CSocketFile类,其实它并不是用来在双方套接口上发送文件的,而是将需要序列化的数据,比如一些结构体数据传给对方。要注意的是CSocketFile类虽然派生自CFile类,但它屏蔽掉了CFile:Open()等函数,也就是说不能调用CSocketFile的Open函数来打开一个实实在在的文件,否则会导致例外。,第9页,10.1 使用MFC类库设计网络程序,10.1.2 MFC中与网络程序设计有关的类 (2)Internet服务器API类(Internet Server API) 在Internet服务器API类中,主要定义了一些与HTTP协议有关的类,这些类是CHtmlStream、CHttpFilter、CHttpFilterContext、CHttpServer和CHttpServerContext。,第10页,10.1 使用MFC类库设计网络程序,10.1.2 MFC中与网络程序设计有关的类 (3)Internet服务类(Internet Serveices) Internet服务类中有与Internet会话有关的CInternetSession类,与Internet连接有关的CInternetConnection类,CInternetConnection有3个派生类,它们是CFtpConnection、CGopherConnection和CHttpConnection。与查找文件有关的CFileFind类,该类有两个派生类,它们是CFtpFileFind和CGopherFileFind类。这些类的具体功能与使用方法在10.2节的实例中介绍。,第11页,10.1 使用MFC类库设计网络程序,10.1.2 MFC中与网络程序设计有关的类 (4)Windows套接口类(Windows Sockets) MFC中定义了一个Windows套接口程序设计类CAsyncSocket,MFC还定义了一个派生于CAsyncSocket的CSocket类,这两个类简单易用,用户可以使用它们来实现自己的网络程序。 以上四种类型的类中,Windows套接口类是最基本的,也是最常用的网络程序设计类,本节就以Windows套接口类程序设计类为例介绍MFC网络程序设计,至于其他的三种类,读者可以参考其他的有关资料。,第12页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 1. CAsyncSocket类 CAsyncSocket类是一个异步非阻塞套接口程序设计类,它封装了一些基本的Windows Sockets API函数,这些函数提供了与较低层Windows Sockets对话的接口。常用的函数有: (1)Accept()函数 Virtual BOOL Accept(CAsyncSocket 该函数用于在一个套接口上接受连接请求。rConnectedSocket参数为监听套接口,lpSockAddr参数为指向地址的指针,其初始值为空,在连接建立后保存远程套接口的IP地址,lpSockAddrLen参数为指向客户套接口地址长度的指针。,第13页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (2)AsyncSelect()函数 BOOL AsyncSelect(long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE ); 该函数用于在套接口准备好之后,请求网络事件通知。网络事件的含义见表10-1所示:,第14页,10.1 使用MFC类库设计网络程序,第15页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (3)Attach()函数 BOOL Attach(SOCKET hSocket, long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE ); 其中hSocket参数为套接口句柄。该函数的作用是将一个套接口句柄连接到一个CAsyncSocket对象实例上,即建立两者的关联,这样就可以实现与另一台计算机的连接了。,第16页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (4)Bind()函数 BOOL Bind( UINT nSocketPort, LPCTSTR lpszSocketAddress = NULL ); BOOL Bind ( const SOCKADDR* lpSockAddr, int nSockAddrLen ); 该函数用于建立一个本地地址与一个套接口的关联,即进行套接口与本了地址的绑定。它有两种调用格式,第一种调用格式提供套接口、端口号和地址,使用字符串形式的地址,一般常用的是这种调用方法。第二种调用格式提供SOCKADDR结构类型的地址参数。,第17页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (5)Close()函数 virtual void Close( ); 该函数用于关闭套接口,释放与套接口有关的系统资源。要注意的是Close()函数是在对象被删除时由CAsyncSocket的析构函数自动调用的。Close()函数的行为取决于套接口的SO_LINGER和SO_DONTLINGER选项。,第18页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (6)Connect()函数 BOOL Connect( LPCTSTR lpszHostAddress, UINT nHostPort ); BOOL Connect( const SOCKADDR* lpSockAddr, int nSockAddrLen ); 该函数用于建立与远程套接口的连接。它有两种调用格式,第一种调用格式使用套接口、端口号和地址,且地址使用参数为字符串型的地址参数,例如“”,或点分十进制的地址,如“”。第二种调用格式提供SOCKADDR结构类型的地址参数。,第19页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (7)Create()函数 BOOL Create( UINT nSocketPort = 0, int nSocketType = SOCK_STREAM, long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE, LPCTSTR lpszSocketAddress = NULL ); 在调用CAsyncSocket的构造函数创建了CAsyncSocket对象后,需要调用Create()函数来创建底层的套接口。因为CAsyncSocket的构造函数没有带参数,所以它只创建一个新的空套接口对象,创建底层套接口的真正工作是由Create()函数来完成的。 其中,函数的第一个参数nSocketPort用于指定一个分配给套接口的端口号,其默认值为0,其真正的含义是告诉系统,可以由系统给该套接口分配一个端口号。在开发服务器程序时应该明确的分配一个端口号(即前面介绍的“众所周知”的端口号,这样客户就可以方便的使用该端口号与服务器连接。在开发客户程序时就可以使用默认的0值,即由系统自动分配一个端口号。 函数的第二个参数nSocketType用来是指定流式(SOCK_STREAM)还是数据报式(SOCK_DGRAM)套接口。 第三个参数lEvent用来指定一个将为应用程序生成通知的事件。在默认情况下,所有的事件都会生成通知。 最后一个参数lpszSocketAddress允许我们为套接口指定一个网络地址,其默认值为0,表示套接口的地址将限定为本地机。该地址以点分十进制的形式给定,如“”。 (8)Detach()函数 SOCKET Detach( ); 该函数作用是将上一次建立关联的套接口句柄断开,并返回此套接口句柄。 (9)FromHandle()函数 static * PASCAL FromHandle( SOCKET hSocket ); 该函数的hSocket参数指定一个套接口的句柄,其作用是返回与此套接口关联的CAsyncSocket对象的指针。如果没有与此套接口关联的CAsyncSocket对象,则返回值为空(NULL)。 (10)GetLastError()函数 static int GetLastError( ); 在实际应用中,当调用的操作失败后用于返回套接口的错误代码。 (11)GetPeerName()函数 BOOL GetPeerName( CString 该函数是一个需要重载的回调函数,当一个套接口已经准备好数据,并可以由函数Receive()接收时,就可以调用此函数处理相应的消息。,第20页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (7)Create()函数 BOOL Create( UINT nSocketPort = 0, int nSocketType = SOCK_STREAM, long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE, LPCTSTR lpszSocketAddress = NULL ); 在调用CAsyncSocket的构造函数创建了CAsyncSocket对象后,需要调用Create()函数来创建底层的套接口。因为CAsyncSocket的构造函数没有带参数,所以它只创建一个新的空套接口对象,创建底层套接口的真正工作是由Create()函数来完成的。,第21页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (7)Create()函数 BOOL Create( UINT nSocketPort = 0, int nSocketType = SOCK_STREAM, long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE, LPCTSTR lpszSocketAddress = NULL ); 在调用CAsyncSocket的构造函数创建了CAsyncSocket对象后,需要调用Create()函数来创建底层的套接口。因为CAsyncSocket的构造函数没有带参数,所以它只创建一个新的空套接口对象,创建底层套接口的真正工作是由Create()函数来完成的。 其中,函数的第一个参数nSocketPort用于指定一个分配给套接口的端口号,其默认值为0,其真正的含义是告诉系统,可以由系统给该套接口分配一个端口号。在开发服务器程序时应该明确的分配一个端口号(即前面介绍的“众所周知”的端口号,这样客户就可以方便的使用该端口号与服务器连接。在开发客户程序时就可以使用默认的0值,即由系统自动分配一个端口号。 函数的第二个参数nSocketType用来是指定流式(SOCK_STREAM)还是数据报式(SOCK_DGRAM)套接口。 第三个参数lEvent用来指定一个将为应用程序生成通知的事件。在默认情况下,所有的事件都会生成通知。 最后一个参数lpszSocketAddress允许我们为套接口指定一个网络地址,其默认值为0,表示套接口的地址将限定为本地机。该地址以点分十进制的形式给定,如“”。 (8)Detach()函数 SOCKET Detach( ); 该函数作用是将上一次建立关联的套接口句柄断开,并返回此套接口句柄。 (9)FromHandle()函数 static * PASCAL FromHandle( SOCKET hSocket ); 该函数的hSocket参数指定一个套接口的句柄,其作用是返回与此套接口关联的CAsyncSocket对象的指针。如果没有与此套接口关联的CAsyncSocket对象,则返回值为空(NULL)。 (10)GetLastError()函数 static int GetLastError( ); 在实际应用中,当调用的操作失败后用于返回套接口的错误代码。 (11)GetPeerName()函数 BOOL GetPeerName( CString 该函数是一个需要重载的回调函数,当一个套接口已经准备好数据,并可以由函数Receive()接收时,就可以调用此函数处理相应的消息。,第22页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 其中,函数的第一个参数nSocketPort用于指定一个分配给套接口的端口号,其默认值为0,其真正的含义是告诉系统,可以由系统给该套接口分配一个端口号。在开发服务器程序时应该明确的分配一个端口号(即前面介绍的“众所周知”的端口号,这样客户就可以方便的使用该端口号与服务器连接。在开发客户程序时就可以使用默认的0值,即由系统自动分配一个端口号。 函数的第二个参数nSocketType用来是指定流式(SOCK_STREAM)还是数据报式(SOCK_DGRAM)套接口。 第三个参数lEvent用来指定一个将为应用程序生成通知的事件。在默认情况下,所有的事件都会生成通知。 最后一个参数lpszSocketAddress允许我们为套接口指定一个网络地址,其默认值为0,表示套接口的地址将限定为本地机。该地址以点分十进制的形式给定,如“”。,第23页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (8)Detach()函数 SOCKET Detach( ); 该函数作用是将上一次建立关联的套接口句柄断开,并返回此套接口句柄。 (9)FromHandle()函数 static * PASCAL FromHandle( SOCKET hSocket ); 该函数的hSocket参数指定一个套接口的句柄,其作用是返回与此套接口关联的CAsyncSocket对象的指针。如果没有与此套接口关联的CAsyncSocket对象,则返回值为空(NULL)。 (10)GetLastError()函数 static int GetLastError( ); 在实际应用中,当调用的操作失败后用于返回套接口的错误代码。,第24页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (11)GetPeerName()函数 BOOL GetPeerName( CString 对于指定的套接口调用GetPeerName()函数,就可以返回与之对应的远程套接口的IP地址和端口号。远程套接口的IP地址和端口号分别由rPeerAddress和rPeerPort参数返回,也可以由指向SOCKADDR结构的参数lpSockAddr返回,第25页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (12)GetSockName()函数 BOOL GetSockName( CString 该函数的作用与GetPeerName()函数类似,对于给定的套接口,就可以返回其IP地址和端口号。IP地址和端口号分别由rSocketAddress和rSocketPort参数返回,也可以由指向SOCKADDR结构的参数lpSockAddr返回。,第26页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (13)GetSockOpt()函数 BOOL GetSockOpt( int nOptionName, void* lpOptionValue, int* lpOptionLen, int nLevel = SOL_SOCKET ); 该函数用于返回一个套接口的选项。获取的选项值由参数lpOptionValue确定,其长度由lpOptionLen指针指向的值确定。nOptionName参数指出要获取的选项名,nLevel参数说明选项级别,默认的选项级别是SOL_SOCKET,该函数仅支持SOL_SOCKET和IPPROTO_TCP两个选项级别。,第27页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (14)SetSockOpt()函数 BOOL SetSockOpt( int nOptionName, const void* lpOptionValue, int nOptionLen, int nLevel = SOL_SOCKET ); 该函数的作用与GetSockOpt()函数相反,用于设置一个套接口的选项。只是要设置的选项值由参数lpOptionValue确定,其它参数的含义与GetSockOpt()函数相同。 (15)IOCtl()函数 BOOL IOCtl( long lCommand, DWORD* lpArgument ); 该函数用于设置套接口的工作模式。,第28页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (16)Listen()函数 BOOL Listen( int nConnectionBacklog = 5 ); 该函数用于连接的监听,当调用成功时返回一个非0的值。参数nConnectionBacklog的取值区间为1到5,默认值为5,它指出正在等待连接的最大队列长度。 (17)OnAccept()函数 virtual void OnAccept( int nErrorCode ); 该函数是一个需要重载的回调函数,当一个套接口可能需要与另一端建立连接时,可以调用此函数处理相应的消息。参数nErrorCode指出最新的错误代码。,第29页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (18)OnClose()函数 virtual void OnClose( int nErrorCode ); 该函数是一个需要重载的回调函数,当一个套接口关闭时,可以调用此函数处理相应的消息。 (19)OnConnect()函数 virtual void OnConnect( int nErrorCode ); 该函数是一个需要重载的回调函数,当一个套接口成功建立连接或连接失败时,可以调用此函数处理相应的消息。,第30页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (20)OnOutOfBandData()函数 virtual void OnOutOfBandData( int nErrorCode ); 该函数是一个需要重载的回调函数,如果一些非常急需的数据已经准备好,就会发出相应的消息,这一类消息的处理需要由该函数完成。 (21)OnReceive()函数 virtual void OnReceive( int nErrorCode ); 该函数是一个需要重载的回调函数,当一个套接口已经准备好数据,并可以由函数Receive()接收时,就可以调用此函数处理相应的消息。,第31页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (20)OnOutOfBandData()函数 virtual void OnOutOfBandData( int nErrorCode ); 该函数是一个需要重载的回调函数,如果一些非常急需的数据已经准备好,就会发出相应的消息,这一类消息的处理需要由该函数完成。 (21)OnReceive()函数 virtual void OnReceive( int nErrorCode ); 该函数是一个需要重载的回调函数,当一个套接口已经准备好数据,并可以由函数Receive()接收时,就可以调用此函数处理相应的消息。,第32页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (22)OnSend()函数 virtual void OnSend( int nErrorCode ); 该函数是一个需要重载的回调函数,当一个套接口已经准备好数据,并可以由Send()函数发送时,就可以调用该函数处理相应的消息。,第33页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (23)Receive()函数 virtual int Receive( void* lpBuf, int nBufLen, int nFlags = 0 ); 该函数用于获得已经与当前套接口建立连接的远程套接口发送的数据。数据存入lpBuf缓冲区中。 (24)ReceiveFrom()函数 int ReceiveFrom( void* lpBuf, int nBufLen, CString 该函数用于从无连接的远程套接口上读取数据报信息。,第34页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (25)Send()函数 virtual int Send( const void* lpBuf, int nBufLen, int nFlags = 0 ); 该函数用于向与当前套接口已经建立连接的远程套接口发送数据。 (26)SendTo()函数 int SendTo( const void* lpBuf, int nBufLen, UINT nHostPort, LPCTSTR lpszHostAddress = NULL, int nFlags = 0 ); int SendTo( const void* lpBuf, int nBufLen, const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags = 0 ); 该函数用于向无连接的远程套接口发送数据。,第35页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (27)ShutDown()函数 BOOL ShutDown( int nHow = sends ); 调用该函数并不影响套接口的打开状态,它不关闭套接口,只可以控制是否能够继续发送或接收数据,即是否允许继续调用Send()和Receive()函数。,第36页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 2 CSocket类 CSocket类派生于CAsyncSocket类,它继承了父类中一些常用易懂的Windows Sockets API函数,并对CAsyncSocket中底层的较难控制的一些API函数或成员函数进行了处理,为Winsock API提供了一个更高级别的编程接口。它通过MFC CArchive对象进行信息的接收和发送操作,使得套接口数据输入和输出如同使用MFC的文档一样简捷易用。同时它支持模块化的后台信息处理,解决了CAsyncSocket中较难克服的多线程处理。 CSocket类提供了如下的一些常用函数: (1)Attach()函数 BOOL Attach( SOCKET hSocket ); 该函数将一个套接口句柄连接到一个CSocket对象实例上,从而可以建立与另一端的连接。,第37页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (2)Create()函数 BOOL Create( UINT nSocketPort = 0, int nSocketType = SOCK_STREAM, LPCTSTR lpszSocketAddress = NULL ); 在调用了CSocket的构造函数(该构造函数不带参数)创建了一个空的CSocket后,再调用Create()函数完成具体的初始化工作。该函数的三个参数都有默认值,对客户机套接口来说,使用默认参数就可以了。但对服务器套接口来说,通常还要为套接口指定一个端口号。 该函数的默认套接口类型是SOCK_STREAM,即流式套接口,当然在程序中我们还可以使用数据报套接口SOCK_DGRAM。但要注意如果我们打算使用CArchive对象时,必须使用默认的套接口类型SOCK_DGRAM。,第38页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (3)FromHandle()函数 static CSocket* PASCAL FromHandle( SOCKET hSocket ); 该函数的参数指出一个套接口句柄,在调用后返回与此套接口关联的CSocket对象指针。如果没有与此套接口关联的对象,则返回NULL。 (4)IsBlocking()函数 BOOL IsBlocking( ); IsBlocking()函数调用后返回一个布尔值,作用为判断在当前时刻套接口是否处于阻塞状态,即是否在等待某种事件的发送。,第39页,10.1 使用MFC类库设计网络程序,10.1.3 MFC中的Windows套接口类 (5)CancelBlockingCall()函数 void CancelBlockingCall( ); 如果套接口处于阻塞状态,那么调用CancelBlockingCall()函数后,所有套接口的阻塞请求被删除。 (6)OnMessagePending()函数 virtual BOOL OnMessagePending( ); 该函数是一个需要重载的虚函数,当套接口处于阻塞状态时,调用OnMessagePending()函数可以处理应用中的其它消息。,第40页,10.2 使用WinInet设计客户端程序,10.2.1 WinInet程序设计知识 1. WinInet编程的简介 WinInet的最大优点是提供了对普通Internet协议的访问功能,这些协议包括HTTP、FTP和Gopher。这样程序员使用WinInet可以编写出高水平的Internet客户端程序,而不必去了解Winsock、TCP/IP和特定Internet协议的细节。这为那些对Internet协议了解不多,但又想设计Internet应用程序的人员提供了极大的方便。WinInet还为这三种协议提供了统一的函数集,既Win32 API接口。如果底层协议改变(如从FTP到HTTP),利用统一的函数集,只用修改少量的代码就可以完成这种改变。,第41页,10.2 使用WinInet设计客户端程序,10.2.1 WinInet程序设计知识 在VC+中,提供了两种使用WinInet的方法: 调用Win32 Internet函数; 使用VC+提供的WinInet类库。MFC将WinInet封装在一个标准的、易于使用的类集合中。 在编写WinInet客户端程序时,既可以直接调用WinInet函数,也可以使用WinInet类库。 下面我们首先介绍WinInet函数,然后再讨论如何使用WinInet类库。在介绍WinInet函数之前,我们先介绍几个与WinInet函数有关的概念。,第42页,10.2 使用WinInet设计客户端程序,10.2.1 WinInet程序设计知识 (1)WinInet中句柄的概念 使用MFC进行程序设计的人员对句柄的概念应该比较熟悉。在WinInet中程序设计中,经常会涉及到句柄的概念。 在WinInet函数中,使用一个特殊的HINTERNET型句柄,该句柄一般表示Internet一个对话、连接、打开或查询调用的结果等内容。要注意它们不能与其他Win32函数使用的文件句柄相互交换使用,如在调用ReadFile()时就不能使用HINTERNET句柄,在调用InternetReadFile()时也不能使用由CreatFile()返回的句柄。 HINTERNET句柄与其他的Win32句柄的重要区别在于Internet句柄被安排在一个树型体系结构中,由InternetOpen()返回的对话句柄是该树型体系的主干,由InternetConnect()返回的连接句柄是该体系的分支,指向格式文件的句柄和查询结果构成该树型体系的树叶。,第43页,10.2 使用WinInet设计客户端程序,10.2.1 WinInet程序设计知识 句柄可以从派生出它的句柄继承属性,例如在异步方法下,我们只需调用一次InternetCloseHandle()来关闭所有的分支句柄,由它派生出的所有句柄都将关闭。 根据句柄的具体类型,HINTERNET句柄可有许多不同的选项与之相联系,这些选项可以通过InternetQueryOption()和InterSetOption()来访问。它们可以用来访问如下信息:句柄的具体类型、超时设置、回调、环境变量、缓冲区大小以及其它设置。,第44页,10.2 使用WinInet设计客户端程序,10.2.1 WinInet程序设计知识 (2)WinInet中错误的处理 在程序中调用WinInet函数时,如果调用成功则返回一个有效的句柄;如果调用失败则函数返回FALSE或NULL。在函数调用失败时可以调用GetLastError()函数得到具体的错误信息。当GetLastError()函数返回的错误信息是ERROR_INTERNET_EXTENDED_ERROR时,对于FTP或Gopher服务器,可进一步通过调用InternetGetLastResponseInfo()函数得到更多的信息。对于HTTP操作,可以使用InternetErrorDlg()函数来显示一个错误信息对话框,允许用户对如何处理错误做出选择。,第45页,10.2 使用WinInet设计客户端程序,10.2.1 WinInet程序设计知识 (3)WinInet函数缓冲区参数的含义 许多WinInet API函数使用指针(lpszBuffer)参数和缓冲区长度(lpdwBufferLength)参数返回一个可变长度的字符串。在传送的缓冲区大小不能容纳返回的字符串时(或指针为NULL),函数调用将失败。如果使用GetLastError()函数将返回ERROR_INSUFFICIENT_BUFFER错误。 (4)WinInet函数的异步I/O操作 WinInet函数的默认操作是同步操作,但这对于完成时间不确定的一些操作是不合适的,因此如果要使用异步操作,可以通过调用InterOpen()函数打开一个对话时,设置一个叫INTERNET_FLAG_ASYNC标志来完成。,第46页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 这里的基本WinInet函数是指在编写HTTP、FTP和gopher程序时都可以使用的一些WinInet函数,它们是使用WinInet API进行程序设计的基础。 下面我们介绍这些基本函数。首先说明一下函数的参数问题,在基本函数中,参数前的IN表示该参数是输入参数,OUT表示该参数是输出参数,既有IN又有OUT的则表示调用函数时,该参数是输入参数,用来给函数提供数据,函数调用完成时它是输出参数,用来从函数体返回一些值。,第47页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 (1)打开一个WinInet对话 大多数的WinInet函数在使用之前,必须首先调用InternetOpen()函数,以打开一个新的对话,然后在调用其他函数时以该函数返回的句柄为做为输入参数,只有这样才可以进行其他的操作。该函数的调用格式如下: HINTERNET InternetOpen( IN LPCTSTR lpszAgent, IN DWORD dwAccessType, IN LPCTSTR lpszProxyName, IN LPCTSTR lpszProxyBypass, IN DWORD dwFlags );,第48页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 该函数在WinInet应用程序中是第一个被调用的函数,它的功能是初始化WinInet库和数据结构,为其他WinInet调用做好准备。在WinInet中,当对话操作完成以后,应该使用InternetCloseHandle()函数关闭该对话句柄,以释放与该对话句柄相关的资源。 InternetOpen函数中,各参数的含义是: lpszAgent:在HTTP协议中是用户代理的名字,例如Microsoft Internet Explorer。,第49页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 dwAccessType:表示存取类型,它可设置为: 1) INTERNET_OPEN_TYPE_DIRECT:表示在本地解决所有的主机名问题。 2) 当设置为INTERNET_OPEN_TYPE_PRECONFIG:表示获取代理或从注册表直接配置。 3) 设置为INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY:表示获取代理或从注册表直接配置并防止 startup的使用。 4) 设置为INTERNET_OPEN_TYPE_PROXY:表示用代理服务器发送请求。 ,第50页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 (2)与服务器建立连接 为了与FTP、HTTP或Gopher服务器进行通信,客户机首先应该与服务器建立连接。与服务器建立连接的函数是InternetConnect(),它的原型如下: HINTERNET InternetConnect( IN HINTERNET hInternet, IN LPCTSTR lpszServerName, IN INTERNET_PORT nServerPort, IN LPCTSTR lpszUserName, IN LPCTSTR lpszPassword, IN DWORD dwService, IN DWORD dwFlags, IN DWORD_PTR dwContext );,第51页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 该函数调用成功后返回一个对FTP、HTTP或Gopher会话的HINTERNET型连接句柄,该连接句柄是由调用InternetOpen()函数时所创建的对话句柄派生出来的,它继承了对话句柄的属性。 要注意对于FTP协议,调用InternetConnect()函数时将与服务器建立一条真正的连接,而对于HTTP和Gopher协议来说,到指定的服务器请求进行时,才建立连接。,第52页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 (4)回调函数 前面说过,WinInet函数在默认情况下是同步操作的,如果要异步使用,在对话句柄由InternetOpen()创建时,必须将dwFlags参数设置为INTERNET_FLAG_ASYN,还要指定一个环境变量,并为句柄指定一个返回函数,而该返回函数通过InternetSetStatusCallback()函数调用与一个句柄连接,InternetSetStatusCallback()的原型如下: INTERNET_STATUS_CALLBACK InternetSetStatusCallback( IN HINTERNET hInternet, IN INTERNET_STATUS_CALLBACK lpfnInternetCallback );,第53页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 (4)回调函数 该函数的hInternet参数指定一个将在由lpfnInternetCallback指定的回调函数中使用的句柄,由该句柄派生出的所有的句柄,在呼叫被连接之后,将继续使用该回调函数。 由lpfnInternetCallback参数指定的返回函数的原型如下: VOID (CALLBACK * INTERNET_STATUS_CALLBACK)( IN HINTERNET hInternet, IN DWORD_PTR dwContext, IN DWORD dwInternetStatus, IN LPVOID lpvStatusInformation, IN DWORD dwStatusInformationLength );,第54页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 (5)通用文件操作 在WinInet API中定义的大部分函数,在调用之前先要与服务器之间建立连接,然而WinInet API中定义的InternetOpenUrl()函数提供了一种从FTP、HTTP或Gopher服务器获取数据的简单方法,即以一种通用的方法调用InternetOpenUrl()函数,该函数的原型如下: HINTERNET InternetOpenUrl( IN HINTERNET hInternet, IN LPCTSTR lpszUrl, IN LPCTSTR lpszHeaders, IN DWORD dwHeadersLength, IN DWORD dwFlags, IN DWORD_PTR dwContext );,第55页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 (6)数据读取操作 对于一个已经打开的句柄,可以调用InternetReadFile()函数来读取数据。读取数据的句柄,可以是由InternetOpenUrl()、FtpOpenFile()、GopherOpenFile()或HttpOpenRequest()函数创建的。该函数的原型如下: BOOL InternetReadFile( IN HINTERNET hFile, IN LPVOID lpBuffer, IN DWORD dwNumberOfBytesToRead, OUT LPDWORD lpdwNumberOfBytesRead );,第56页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 (7)向Internet文件写数据 我们可以调用InternetWriteFile()函数向一个打开的Internet文件写数据,该函数的原型如下: BOOL InternetWriteFile( IN HINTERNET hFile, IN LPCVOID lpBuffer, IN DWORD dwNumberOfBytesToWrite, OUT LPDWORD lpdwNumberOfBytesWritten );,第57页,10.2 使用WinInet设计客户端程序,2 基本WinInet函数 (8)移动Internet文件指针 调用InternetReadFile()读取文件数据时,可以调用InternetSetFilePointer()函数来设置一个文件的指针位置,用来控制读取数据的位置。该函数的原型如下: DWORD InternetSetFi

温馨提示

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

评论

0/150

提交评论