以下介绍的类和相关函数全部属于WinINet,WinInet全称是Win32 Internet Extension,它提供一个通用的网络协议访问接口,关于WinInet的整体介绍参考WinINet基础。
需要用到的WinINet class:
CInternetSession
CInternetSession用来创建和初始化Internet会话,MSDN的解释是:“Creates and initializes a single or several simultaneous(同步、同时) Internet sessions and, if necessary, describes your connection to a proxy server.”。
主要用到的方法有:GetHttpConnection()、OpenURL()、Close()。
1. GetHttpConnection()
GetHttpConnection()方法用来完成HTTP连接,并返回一个CHttpConnection对象,“Call this member function to establish an HTTP connection and get a pointer to a CHttpConnection object.”。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
CHttpConnection
*
GetHttpConnection
(
LPCTSTR
pstrServer
,
INTERNET_PORT
nPort
=
INTERNET_INVALID_PORT_NUMBER
,
LPCTSTR
pstrUserName
=
NULL
,
LPCTSTR
pstrPassword
=
NULL
)
;
CHttpConnection
*
GetHttpConnection
(
LPCTSTR
pstrServer
,
DWORD
dwFlags
,
INTERNET_PORT
nPort
=
INTERNET_INVALID_PORT_NUMBER
,
LPCTSTR
pstrUserName
=
NULL
,
LPCTSTR
pstrPassword
=
NULL
)
;
|
典型应用:
1
2
3
|
CInternetSession
httpSession
;
CHttpConnection
*
pHttpConnection
=
httpSession
.
GetHttpConnection
(“
www
.
zhuyanfeng
.
com”
)
;
|
2. OpenURL()
OpenURL() 方法用来向HTTP服务器发送指定的请求,“Call this member function to send the specified request to the HTTP server and allow the client to specify additional RFC822, MIME, or HTTP headers to send along with the request. ”。
1
2
3
4
5
6
7
|
CStdioFile
*
OpenURL
(
LPCTSTR
pstrURL
,
DWORD_PTR
dwContext
=
1
,
DWORD
dwFlags
=
INTERNET_FLAG_TRANSFER_ASCII
,
LPCTSTR
pstrHeaders
=
NULL
,
DWORD
dwHeadersLength
=
0
)
;
|
典型应用:
1
2
3
4
5
6
7
8
9
10
11
|
CInternetSession
session
;
CHttpFile
*
file
=
NULL
;
file
=
(
CHttpFile
*
)
session
.
OpenURL
(
_T
(
"http://www.microsoft.com"
)
)
;
if
(
NULL
!=
file
)
{
//Do something here with the web request
//Clean up the file here to avoid a memory leak!!!!!!!
file
->
Close
(
)
;
delete
file
;
}
session
.
Close
(
)
;
|
3. Close()
“Call this member function when your application has finished using the CInternetSession object.”。
典型应用:
1
2
3
|
CInternetSession
session
;
// …
session
.
Close
(
)
;
|
CHttpConnection
CHttpConnection用来管理HTTP连接,“Manages your connection to an HTTP server.”。
主要用到的方法有:OpenRequest ()、Close()。
1. OpenRequest ()
OpenRequest ()方法用来打开一个HTTP连接,并返回一个指向CHttpFile对象的指针,“Call this member function to open an HTTP connection.”。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
CHttpFile
*
OpenRequest
(
LPCTSTR
pstrVerb
,
LPCTSTR
pstrObjectName
,
LPCTSTR
pstrReferer
=
NULL
,
DWORD_PTR
dwContext
=
1
,
LPCTSTR
*
ppstrAcceptTypes
=
NULL
,
LPCTSTR
pstrVersion
=
NULL
,
DWORD
dwFlags
=
INTERNET_FLAG_EXISTING_CONNECT
)
;
CHttpFile
*
OpenRequest
(
int
nVerb
,
LPCTSTR
pstrObjectName
,
LPCTSTR
pstrReferer
=
NULL
,
DWORD_PTR
dwContext
=
1
,
LPCTSTR
*
ppstrAcceptTypes
=
NULL
,
LPCTSTR
pstrVersion
=
NULL
,
DWORD
dwFlags
=
INTERNET_FLAG_EXISTING_CONNECT
)
;
|
其中Verb参数代表HTTP的请求方式(HTTP request type),可以设置为:HTTP_VERB_POST、HTTP_VERB_GET等等。MSDN中讲到:“If NULL, “GET” is used.”,但这种说法应该是不准确的,如果该参数设置为NULL,将使用“POST”方式,因为HTTP_VERB_POST被定义为0。而如果给该参数传递NULL指针,将触发一个assertion。ObjectName参数用于指定要请求的目标对象(target object),比如一个指定的文件。Version参数是HTTP协议版本,如果设置为NULL,将使用“HTTP/1.0”。
典型应用:
1
2
3
4
5
6
|
CHttpFile
*
pHttpFile
=
pHttpConnection
->
OpenRequest
(
CHttpConnection
::
HTTP_VERB_POST
,
“
/
index
.
html”
)
;
CHttpFile
*
pHttpFile
=
pHttpConnection
->
OpenRequest
(
HTTP_VERB_POST
,
szObject
,
NULL
,
1
,
NULL
,
"HTTP/1.1"
,
INTERNET_FLAG_EXISTING_CONNECT
|
INTERNET_FLAG_NO_AUTO_REDIRECT
)
;
|
2. Close ()
Close()方法通常不使用,因为对于HTTP 1.1协议,有个keep-alive的属性, 就是所谓的持久连接,对于http这种大量的短连接的服务来说,开启持久连接可以节省大量的TCP连接过程的开销。一般可以在HTTP连接的使命结束之后调用Close()方法,例如自己封装的HTTP操作类的析构函数中。
典型应用:
1
2
3
4
|
if
(
NULL
!=
pHttpConnection
)
{
pHttpConnection
->
Close
(
)
;
}
|
CHttpFile
CHttpFile提供从HTTP服务器请求和读取文件的功能(函数),“Provides the functionality to request and read files on an HTTP server.”。
主要用到的方法有:AddRequestHeaders()、SendRequest()、QueryInfoStatusCode()、Read()、ReadString()、Close()。其中Read()、ReadString()和Close()继承自父类CInternetFile。
1. AddRequestHeaders ()
AddRequestHeaders () 方法用来给请求添加Headers,“Adds headers to the request sent to an HTTP server.”。
1
2
3
4
5
6
7
8
9
|
BOOL
AddRequestHeaders
(
LPCTSTR
pstrHeaders
,
DWORD
dwFlags
=
HTTP_ADDREQ_FLAG_ADD_IF_NEW
,
int
dwHeadersLen
=
-
1
)
;
BOOL
AddRequestHeaders
(
CString
&
str
,
DWORD
dwFlags
=
HTTP_ADDREQ_FLAG_ADD_IF_NEW
)
;
|
典型应用:
1
2
3
4
5
|
pHttpFile
->
AddRequestHeaders
(
"Accept: *,*/*"
)
;
pHttpFile
->
AddRequestHeaders
(
"Accept-Language: zh-cn"
)
;
pHttpFile
->
AddRequestHeaders
(
"Content-Type: application/x-www-form-urlencoded"
)
;
pHttpFile
->
AddRequestHeaders
(
"Accept-Encoding: gzip, deflate"
)
;
|
2. SendRequest ()
SendRequest() 方法用来向HTTP服务器发送一个请求,“Call this member function to send a request to an HTTP server.”。
1
2
3
4
5
6
7
8
9
10
11
|
BOOL
SendRequest
(
LPCTSTR
pstrHeaders
=
NULL
,
DWORD
dwHeadersLen
=
0
,
LPVOID
lpOptional
=
NULL
,
DWORD
dwOptionalLen
=
0
)
;
BOOL
SendRequest
(
CString
&
strHeaders
,
LPVOID
lpOptional
=
NULL
,
DWORD
dwOptionalLen
=
0
)
;
|
典型应用:
1
2
|
pHttpFile
->
SendRequest
(
NULL
,
0
,
(
LPVOID
)
(
LPCTSTR
)
strPostData
,
strPostData
==
NULL
?
0
:
_tcslen
(
strPostData
)
)
;
|
3. QueryInfoStatusCode ()
QueryInfoStatusCode ()方法用来获取一个HTTP请求的状态码,“Retrieves the status code associated with an HTTP request”。
1
2
3
|
BOOL
QueryInfoStatusCode
(
DWORD
&
dwStatusCode
)
const
;
|
典型应用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
DWORD
dwRet
;
pHttpFile
->
QueryInfoStatusCode
(
dwRet
)
;
if
(
dwRet
==
HTTP_STATUS_OK
)
{
CFile
file
;
file
.
Open
(“
url
.
html”
,
CFile
::
modeCreate
|
CFile
::
modeReadWrite
)
;
char
buf
[
1000
]
=
{
0
}
;
int
nRead
=
0
;
int
nTotal
=
0
;
while
(
(
nRead
=
pHttpFile
->
Read
(
buf
,
sizeof
(
buf
)
)
)
>
0
)
{
file
.
Write
(
buf
,
nRead
)
;
nTotal
+
=
nRead
;
}
file
.
Flush
(
)
;
file
.
Close
(
)
;
CString
szMsg
;
szMsg
.
Format
(“成功读取
%
d个字节”
,
nTotal
)
;
MessageBox
(
szMsg
)
;
}
else
{
CString
szMsg
;
szMsg
.
Format
(“读取网页失败,返回:
%
d”
,
dwRet
)
;
MessageBox
(
szMsg
)
;
}
|
4. Read ()和ReadString()
Read ()和ReadString()方法用来读取字节数据或者字符流。
1
2
3
4
5
6
7
8
9
10
11
|
virtual
UINT
Read
(
void
*
lpBuf
,
UINT
nCount
)
;
virtual
BOOL
ReadString
(
CString
&
rString
)
;
virtual
LPTSTR
ReadString
(
LPTSTR
pstr
,
UINT
nMax
)
;
|
典型应用(Read()参考QueryInfoStatusCode()的典型应用):
1
2
3
4
5
|
CString
szData
,
szTemp
;
while
(
pHttpFile
->
ReadString
(
szTemp
)
)
{
szData
=
szData
+
szTemp
+
"\r\n"
;
}
|
需要注意的地方
(1)CHttpConnection、CHttpFile的指针,在用完之后需要调用其Close()方法,并且还要再delete一下指针,不然会有内存泄露。
(2)如果VC++项目采用Unicode编码,而从HTTP连接Read回来的数据是Multi-Byte编码,那么需要调用MultiByteToWideChar进行编码转换。如果VC++项目本就采用Multi-Byte编码,就不用做这个工作了。
需要用到的WinINet全局函数AfxParseURL
AfxParseURL全局函数用于解析一个URL字符串,并返回服务类型。
1
2
3
4
5
6
7
|
BOOL
AFXAPI
AfxParseURL
(
LPCTSTR
pstrURL
,
//指向要解析的URL字符串的指针
DWORD
&
dwServiceType
,
//表明Internet的服务类型,如AFX_INET_SERVICE_HTTP
CString
&
strServer
,
//解析出来的主机字符串
CString
&
strObject
,
//解析出来的URL内容字符串
INTERNET_PORT
&
nPort
//端口号(由Server或Object段指定的)
)
;
|
如果一个URL解析成功则返回非0值;如果为空URL或者不包含已知的服务类型则返回0值。例如用AfxParseURL解析URL:service://server/dir/dir/object.ext:port,执行成功后得到的值:
1
2
3
4
|
strServer
==
“
server”
strObject
==“
/
dir
/
dir
/
object
.
ext”
nPort
==
#port
dwServiceType
==
#service
|