【转】Windows Internet - WinINet 学习笔记
2009-05-20 09:45
357 查看
原文:http://hi.baidu.com/kun_g/blog/item/206a4023c3cc8542ad34deb1.html1.关于WinINetWinINet
不是给服务端用的,服务端用Microsoft Windows HTTP Services (WinHTTP)WinINet
抽象了Gopher,FTP,HTTP协议的一些细节。2.HINTERNET 句柄
句柄的函数,而白色的框就是使用被创建的 HINTERNET
句柄的函数
来解码了(gzip与deflate)。有三种方式开启解码选项(基于会话、请求、连接),它们的作用域不同。可以使用InternetOpen(基于会话),InternetConnect(基于连接),HttpOpenRequest(基于请求)返回的句柄调用InternetSetOption来打开或关闭解码选项,打开则将 dwOption
参数中INTERNET_OPTION_HTTP_DECODING 选项打开, 令 lpBuffer
指向一个为true的boolean变量. 关闭则dwOption
参数中INTERNET_OPTION_HTTP_DECODING 选项打开, 令 lpBuffer
指向一个为false的boolean变量 .设置解码选项之后, WinInet 在你调用InternetReadFile是就会执行一次解码。不过就算你打开了解码选项,它也不一定就为你解码……当这种情况发生时,InternetReadFile函数会失败并返回ERROR_INTERNET_DECODING_FAILED.这个时候你可以选择去掉Accept-Encoding头重新发送一次请求,或者把解码关掉然后自己来解码(这时你就得检查Content-Encoding头来判断编码方式了)。5.协议无关函数从Internet下载文件 (InternetReadFile,InternetSetFilePointer,InternetFindNextFile,InternetQueryDataAvailable).设置同步操作 (InternetSetStatusCallback).查询、修改设置 (InternetSetOption,InternetQueryOption).关闭HINTERNET句柄 (InternetCloseHandle).锁定、解锁资源文件 (InternetLockRequestFile,InternetUnlockRequestFile).
会返回0字节被读取(lpdwNumberOfBytesRead
参数保存了读取的字节数). 据此,我们就可以循环调用InternetReadFile直到读取结束。
, //InternetOpen 返回的句柄__in LPCTSTR lpszServerName
, //可以描述目标服务器的字符串__in INTERNET_PORT nServerPort
,//目标服务器的端口__in LPCTSTR lpszUsername
,//用户名__in LPCTSTR lpszPassword
,//密码__in DWORD dwService
,//使用的服务类型__in DWORD dwFlags
,__in DWORD_PTRdwContext);nServerPort
ldwService
,// InternetConnect 函数返回的句柄__in LPCTSTR lpszVerb
,// 动作,有GET, PUT, POST。也可以设置为 NULL ,会被当成默认的 GET 来用__in LPCTSTR lpszObjectName
,// 一个描述你请求资源的字符串,当请求一个默认页面时令这个参数指向一个空串__in LPCTSTR lpszVersion
,// HTTP 版本,这个参数为 NULL 时,默认使用""HTTP/1.1""__in LPCTSTR lpszReferer
,// 说明了lpszObjectName是取自哪个文件,可以设为NULL__in LPCTSTR *lplpszAcceptTypes
, //
是一个指向LPCTSTR数组的指针!数组以一个NULL指针结束。指定了程序接受的内容的类型,设为空则不接受 任何类型的内容,设为空串则等价于""text/*"",即不接受文本文件以外的图片等文件,只接受某种特定的文件可以用类似"image/gif, image/jpeg"的方式。关于更多内容类型 请看这里__in DWORD dwFlags
,// 一般都可以设置为 0__in DWORD_PTRdwContext // 一般都可以设置为 0);
,//HttpOpenRequest 返回的句柄__in LPCTSTR lpszHeaders
,//包含要添加到请求中的头的字符串的指针,每个头都要以一个 CR/LF ( /r/n/r/n ) 对结束__in DWORD dwHeadersLength
,//lpszHeaders指向的字符串的长度(以TCHAR类型记). 如果这个参数被设为-1,则字符串被当作以0结尾的字符串处理,自动计算该字符串的长度__in DWORD dwModifiers);dwModifiers可以是下面这些值的组合
(4)发送一个请求HttpSendRequestBOOL HttpSendRequest(__in HINTERNET hRequest
, //HttpOpenRequst 返回的句柄__in LPCTSTR lpszHeaders
, //附加到请求上的头,可以为NULL__in DWORD dwHeadersLength
, //lpszHeaders指向的字符串的长度(以TCHAR类型记). 如果这个参数被设为-1,当调用的是HttpSendRequestA时则字符串被当作以0结尾的字符串处理,自动计算该字符串的长度。当调用的是 HttpSendRequestW时就会产生一个错误__in LPVOID lpOptional
, //当使用POST或PUT方法时,这个参数指向的数据会紧接着请求被发送出去。没有需要发送的数据则可以设置为NULL__in DWORDdwOptionalLength //lpOptional数据的字节长度,无数据时设置为0);
, /*由 HttpOpenRequest 或 InternetOpenUrl 返回的句柄*/__in DWORD dwInfoLevel
,/*Query Info Flags.*/__inout LPVOID lpvBuffer
, /*用于存储查询结果的缓冲区,不可为NULL*/__inout LPDWORD lpdwBufferLength
,/*lpvBuffer指向的缓冲区的字节长度若函数执行成功,这个变量存储的是写到缓冲区里的数据长度。如果数据是字符串则返回的长度不包括字符串的结束字符如果函数发生 ERROR_INSUFFICIENT_BUFFER 错误, 则这个变量里保存的是数据的实际字节长度程序需要根据这个长度重新分配内存,再执行一次这个函数*/__inout LPDWORDlpdwIndex /*没看大明白,不过似乎可以设置为NULLPointer to a zero-based header index used to enumerate multiple headers with the same name.When calling the function, this parameter is the index of the specified header to return.When the function returns, this parameter is the index of the next header.If the next index cannot be found, ERROR_HTTP_HEADER_NOT_FOUND is returned.*/);
BOOL InternetReadFile( //读取句柄的数据__in HINTERNET hFile, // InternetOpenUrl, FtpOpenFile, GopherOpenFile, HttpOpenRequest 创建的句柄__out LPVOID lpBuffer, // 存放数据的缓冲区__in DWORD dwNumberOfBytesToRead, // 准备读取的字节数__out LPDWORD lpdwNumberOfBytesRead // 读取了的字节数);DWORD InternetSetFilePointer( //设置InternetReadFile的文件位置(莫非多线程下载就是用这个实现的?),服务器不支持随机访问的话函数调用会失败,如果InternetReadFile已经读取到了文件的末尾,这个函数的调用也会失败。__in HINTERNET hFile, //由 InternetOpenUrl (on an HTTP or HTTPS URL)创建。 或由HttpOpenRequest 创建(使用 GET 或 HEAD方法,而且句柄已经被 HttpSendRequest 访问过了).这个句柄也不可以使用 INTERNET_FLAG_DONT_CACHE 或 INTERNET_FLAG_NO_CACHE_WRITE 标志__in LONG lDistanceToMove, //移动的字节数。正数向后移动,负数向前移动__in PVOID pReserved, //保留参数,为NULL__in DWORD dwMoveMethod, //指定了移动指针时的参考点。FILE_BEGIN(使用这个标志时,移动的字节数被当作无符号数处理)、FILE_CURRENT、FILE_END(如果内容的长度无法获得,则使用这个标志时会失败)__in DWORD_PTR dwContext //保留参数,为NULL);PS:Evernote里面编辑好的格式贴这里似乎有问题~
不是给服务端用的,服务端用Microsoft Windows HTTP Services (WinHTTP)WinINet
抽象了Gopher,FTP,HTTP协议的一些细节。2.HINTERNET 句柄
WinINet函数创建、使用的句柄都是HINTERNET类型的,这种类型的句柄无法被转换成其它类型的句柄。换句话说,最好别用ReadFile、CloseHandle之类的函数来操作这些句柄。同样的,也别用WinINet函数来访问、操作其他类型的句柄。比如,用InternetReadFile访问CreateFile创建句柄是无法得到你想要的结果的。想关闭HINTERNET句柄要使用InternetCloseHandle函数。
3.句柄架构
InternetOpen创建的句柄在顶层,由接下来的一层的InternetOpenUrl和InternetConnect使用,而InternetConnect创建的句柄又被之后的几个函数使用。下面这张图是依赖InternetOpenUrl创建的句柄的几个函数,灰色的方框是返回 HINTERNET句柄的函数,而白色的框就是使用被创建的 HINTERNET
句柄的函数
FTP Hierarchy
HTTP Hierarchy
注意这张图,这张图的意思是HttpSendRequestEx先访问HttpOpenRequest创建的句柄之后,HttpEndRequest,InternetReadFileEx和InternetWriteFile才能访问这个句柄。HttpEndRequest被调用之后,才轮的到InternetReadFile,InternetSetFilePointer和InternetQueryDataAvailable来访问这个句柄。4.内容编码HTTP 协议 (RFC 2616) 规定了应用程序可以要求服务器用编码的方式(encoded format)返回HTTP响应。在Windows Server 2008 与 Windows Vista之前,发送给应用程序的内容编码了的请求需要应用程序自己处理,从Windows Server 2008 and Windows Vista开始, 应用程序可以让 WinINet来解码了(gzip与deflate)。有三种方式开启解码选项(基于会话、请求、连接),它们的作用域不同。可以使用InternetOpen(基于会话),InternetConnect(基于连接),HttpOpenRequest(基于请求)返回的句柄调用InternetSetOption来打开或关闭解码选项,打开则将 dwOption
参数中INTERNET_OPTION_HTTP_DECODING 选项打开, 令 lpBuffer
指向一个为true的boolean变量. 关闭则dwOption
参数中INTERNET_OPTION_HTTP_DECODING 选项打开, 令 lpBuffer
指向一个为false的boolean变量 .设置解码选项之后, WinInet 在你调用InternetReadFile是就会执行一次解码。不过就算你打开了解码选项,它也不一定就为你解码……当这种情况发生时,InternetReadFile函数会失败并返回ERROR_INTERNET_DECODING_FAILED.这个时候你可以选择去掉Accept-Encoding头重新发送一次请求,或者把解码关掉然后自己来解码(这时你就得检查Content-Encoding头来判断编码方式了)。5.协议无关函数从Internet下载文件 (InternetReadFile,InternetSetFilePointer,InternetFindNextFile,InternetQueryDataAvailable).设置同步操作 (InternetSetStatusCallback).查询、修改设置 (InternetSetOption,InternetQueryOption).关闭HINTERNET句柄 (InternetCloseHandle).锁定、解锁资源文件 (InternetLockRequestFile,InternetUnlockRequestFile).
Function | Description |
InternetFindNextFile | 继续文件的枚举或搜索. 需要以下函数创建的句柄FtpFindFirstFile,GopherFindFirstFile,InternetOpenUrl |
InternetLockRequestFile | 允许用户锁定文件. 需要以下函数创建的句柄FtpOpenFile,GopherOpenFile,HttpOpenRequest,InternetOpenUrl. |
InternetQueryDataAvailable | 查询可用数据的数量. 需要以下函数创建的句柄FtpOpenFile,GopherOpenFile,HttpOpenRequest. |
InternetQueryOption | 查询 Internet 设置. |
InternetReadFile | 读取 URL 数据. 需要以下函数创建的句柄InternetOpenUrl,FtpOpenFile,GopherOpenFile,HttpOpenRequest. |
InternetSetFilePointer | 设置文件指针. 需要以下函数创建的句柄InternetOpenUrl( HTTP URL only)HttpOpenRequest(GET 方法). |
InternetSetOption | 配置 Internet 设置. |
InternetSetStatusCallback | 设置一个接收状态信息的回调函数. 分配一个回调函数给指定的HINTERNET句柄及从其演化而来的句柄. |
InternetUnlockRequestFile | 解锁被InternetLockRequestFile锁定的文件. |
读文件
函数InternetReadFile用来从一个由函数InternetOpenUrl,FtpOpenFile,GopherOpenFile,HttpOpenRequest返回的HINTERNET句柄下载资源.WinINet 提供了两种方法来下载整个资源InternetQueryDataAvailable函数.利用InternetReadFile的返回值InternetQueryDataAvailable使用InternetOpenUrl,FtpOpenFile,GopherOpenFile,HttpOpenRequest(还记得上面的那个图么,这个函数需要在HttpSendRequest操作该句柄之后才能访问这个句柄) 创建的句柄。返回有效数据的字节数,据此,我们就可以分配足够的内存并进行读取,但是这种方法不保险,包头里的长度可能是过时的,而且包头也可能会丢。当所有数据都被读完的时候, InternetReadFile会返回0字节被读取(lpdwNumberOfBytesRead
参数保存了读取的字节数). 据此,我们就可以循环调用InternetReadFile直到读取结束。
寻找文件
先使用FtpFindFirstFile,GopherFindFirstFile, 或InternetOpenUrl,然后将其返回的句柄作为参数 传递给InternetFindNextFile进行继续查找,持续调用InternetFindNextFile知道返回扩展的错误信息ERROR_NO_MORE_FILES来完成整个搜索,调用GetLastError来获取最后的错误信息.6.HTTP 会话使用 WinINet 函数访问WWW资源
(1)初始化 WWW 连接
将服务类型设为 INTERNET_SERVICE_HTTP 调用InternetConnect来建立一个 HTTP 会话
HINTERNET InternetConnect(__in HINTERNET hInternet, //InternetOpen 返回的句柄__in LPCTSTR lpszServerName
, //可以描述目标服务器的字符串__in INTERNET_PORT nServerPort
,//目标服务器的端口__in LPCTSTR lpszUsername
,//用户名__in LPCTSTR lpszPassword
,//密码__in DWORD dwService
,//使用的服务类型__in DWORD dwFlags
,__in DWORD_PTRdwContext);nServerPort
Value | Meaning |
INTERNET_DEFAULT_FTP_PORT | Uses the default port for FTP servers (port 21). |
INTERNET_DEFAULT_GOPHER_PORT | Uses the default port for Gopher servers (port 70). |
INTERNET_DEFAULT_HTTP_PORT | Uses the default port for HTTP servers (port 80). |
INTERNET_DEFAULT_HTTPS_PORT | Uses the default port for Secure Hypertext Transfer Protocol (HTTPS) servers (port 443). |
INTERNET_DEFAULT_SOCKS_PORT | Uses the default port for SOCKS firewall servers (port 1080). |
INTERNET_INVALID_PORT_NUMBER | Uses the default port for the service specified by dwService . |
Value | Meaning |
INTERNET_SERVICE_FTP | FTP service. |
INTERNET_SERVICE_GOPHER | Gopher service. |
INTERNET_SERVICE_HTTP | HTTP service. |
(2)建立请求
调用HttpOpenRequest来建立一个 HTTP 请求,不过这个函数不会自动把请求发送出去,要发送请求需要调用HttpSendRequestHttpOpenRequest原型HINTERNET HttpOpenRequest(__in HINTERNET hConnect,// InternetConnect 函数返回的句柄__in LPCTSTR lpszVerb
,// 动作,有GET, PUT, POST。也可以设置为 NULL ,会被当成默认的 GET 来用__in LPCTSTR lpszObjectName
,// 一个描述你请求资源的字符串,当请求一个默认页面时令这个参数指向一个空串__in LPCTSTR lpszVersion
,// HTTP 版本,这个参数为 NULL 时,默认使用""HTTP/1.1""__in LPCTSTR lpszReferer
,// 说明了lpszObjectName是取自哪个文件,可以设为NULL__in LPCTSTR *lplpszAcceptTypes
, //
是一个指向LPCTSTR数组的指针!数组以一个NULL指针结束。指定了程序接受的内容的类型,设为空则不接受 任何类型的内容,设为空串则等价于""text/*"",即不接受文本文件以外的图片等文件,只接受某种特定的文件可以用类似"image/gif, image/jpeg"的方式。关于更多内容类型 请看这里__in DWORD dwFlags
,// 一般都可以设置为 0__in DWORD_PTRdwContext // 一般都可以设置为 0);
(3)添加请求
HttpAddRequestHeaders原型BOOL HttpAddRequestHeaders(__in HINTERNET hConnect,//HttpOpenRequest 返回的句柄__in LPCTSTR lpszHeaders
,//包含要添加到请求中的头的字符串的指针,每个头都要以一个 CR/LF ( /r/n/r/n ) 对结束__in DWORD dwHeadersLength
,//lpszHeaders指向的字符串的长度(以TCHAR类型记). 如果这个参数被设为-1,则字符串被当作以0结尾的字符串处理,自动计算该字符串的长度__in DWORD dwModifiers);dwModifiers可以是下面这些值的组合
Value | Meaning |
HTTP_ADDREQ_FLAG_ADD | Adds the header if it does not exist. Used with HTTP_ADDREQ_FLAG_REPLACE. |
HTTP_ADDREQ_FLAG_ADD_IF_NEW | Adds the header only if it does not already exist; otherwise, an error is returned. |
HTTP_ADDREQ_FLAG_COALESCE | Coalesces headers of the same name. |
HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA | Coalesces headers of the same name. For example, adding "Accept: text/*" followed by "Accept: audio/*" with this flag results in the formation of the single header "Accept: text/*, audio/*". This causes the first header found to be coalesced. It is up to the calling application to ensure a cohesive scheme with respect to coalesced/separate headers. |
HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON | Coalesces headers of the same name using a semicolon. |
HTTP_ADDREQ_FLAG_REPLACE | Replaces or removes a header. If the header value is empty and the header is found, it is removed. If not empty, the header value is replaced. |
, //HttpOpenRequst 返回的句柄__in LPCTSTR lpszHeaders
, //附加到请求上的头,可以为NULL__in DWORD dwHeadersLength
, //lpszHeaders指向的字符串的长度(以TCHAR类型记). 如果这个参数被设为-1,当调用的是HttpSendRequestA时则字符串被当作以0结尾的字符串处理,自动计算该字符串的长度。当调用的是 HttpSendRequestW时就会产生一个错误__in LPVOID lpOptional
, //当使用POST或PUT方法时,这个参数指向的数据会紧接着请求被发送出去。没有需要发送的数据则可以设置为NULL__in DWORDdwOptionalLength //lpOptional数据的字节长度,无数据时设置为0);
(5)向服务器发送数据
方法一:参见上面HttpSentRequest的lpOptional参数的说明方法二:使用InternetWriteFile向一个句柄里发送数据,然后使用HttpSendRequestEx发送(6)查询一个请求的信息
HttpQueryInfoBOOL HttpQueryInfo(__in HINTERNET hRequest, /*由 HttpOpenRequest 或 InternetOpenUrl 返回的句柄*/__in DWORD dwInfoLevel
,/*Query Info Flags.*/__inout LPVOID lpvBuffer
, /*用于存储查询结果的缓冲区,不可为NULL*/__inout LPDWORD lpdwBufferLength
,/*lpvBuffer指向的缓冲区的字节长度若函数执行成功,这个变量存储的是写到缓冲区里的数据长度。如果数据是字符串则返回的长度不包括字符串的结束字符如果函数发生 ERROR_INSUFFICIENT_BUFFER 错误, 则这个变量里保存的是数据的实际字节长度程序需要根据这个长度重新分配内存,再执行一次这个函数*/__inout LPDWORDlpdwIndex /*没看大明白,不过似乎可以设置为NULLPointer to a zero-based header index used to enumerate multiple headers with the same name.When calling the function, this parameter is the index of the specified header to return.When the function returns, this parameter is the index of the next header.If the next index cannot be found, ERROR_HTTP_HEADER_NOT_FOUND is returned.*/);
(7)从 WWW 上下载资源
在调用HttpOpenRequest和HttpSendRequest之后, 程序可以使用InternetReadFile,InternetQueryDataAvailable,InternetSetFilePointer来下载HTTP服务器上的资源了。BOOL InternetQueryDataAvailable(//查询数据的长度__in HINTERNET hFile
, //由 InternetOpenUrl, FtpOpenFile, GopherOpenFile, 或 HttpOpenRequest返回的句柄__out LPDWORD lpdwNumberOfBytesAvailable
, //用于存放数据长度的指针__in DWORD dwFlags
, //保留参数,置0__in DWORD_PTR dwContext
//保留参数,置0);
BOOL InternetReadFile( //读取句柄的数据__in HINTERNET hFile, // InternetOpenUrl, FtpOpenFile, GopherOpenFile, HttpOpenRequest 创建的句柄__out LPVOID lpBuffer, // 存放数据的缓冲区__in DWORD dwNumberOfBytesToRead, // 准备读取的字节数__out LPDWORD lpdwNumberOfBytesRead // 读取了的字节数);DWORD InternetSetFilePointer( //设置InternetReadFile的文件位置(莫非多线程下载就是用这个实现的?),服务器不支持随机访问的话函数调用会失败,如果InternetReadFile已经读取到了文件的末尾,这个函数的调用也会失败。__in HINTERNET hFile, //由 InternetOpenUrl (on an HTTP or HTTPS URL)创建。 或由HttpOpenRequest 创建(使用 GET 或 HEAD方法,而且句柄已经被 HttpSendRequest 访问过了).这个句柄也不可以使用 INTERNET_FLAG_DONT_CACHE 或 INTERNET_FLAG_NO_CACHE_WRITE 标志__in LONG lDistanceToMove, //移动的字节数。正数向后移动,负数向前移动__in PVOID pReserved, //保留参数,为NULL__in DWORD dwMoveMethod, //指定了移动指针时的参考点。FILE_BEGIN(使用这个标志时,移动的字节数被当作无符号数处理)、FILE_CURRENT、FILE_END(如果内容的长度无法获得,则使用这个标志时会失败)__in DWORD_PTR dwContext //保留参数,为NULL);PS:Evernote里面编辑好的格式贴这里似乎有问题~
相关文章推荐
- 转: Windows Internet - WinINet 学习笔记(2)
- Windows Internet - WinINet 学习笔记(1)
- 转:Windows Internet - WinINet 学习笔记(1)
- Windows Internet - WinINet 学习笔记(2)
- 【深度学习】笔记15 windows下SSD网络在caffe中的配置【笔记1】
- Windows命令行学习笔记
- Memcached学习笔记——windows上初步使用(与java结合)
- Lua学习笔记1:开发环境搭建(windows和linux)
- CoAP学习笔记——nodeJS node-coap安装和使用(windows平台)
- Windows 程序设计学习笔记1
- windows驱动开发详解学习笔记
- C#学习笔记——windows窗体
- 【学习笔记】linux与windows中wchar_t的问题
- Windows驱动开发工具 WDK 学习笔记
- Spark2.x学习笔记:6、在Windows平台下搭建Spark开发环境(Intellij IDEA)
- Windows核心编程学习笔记-------23章
- python3.4学习笔记(十六) windows下面安装easy_install和pip教程
- 大数据学习笔记:windows下hadoop的启动脚本分析,start-all.cmd
- 孙鑫VC学习笔记:第一讲 Windows程序内部运行原理
- windows 服务学习笔记