同步的就不说了,网上和MSDN上有代码。
对于异步的处理,贴上源代码。参考MSDN上面的代码和网上一些前辈的代码。
加上了我自己的一些理解和注释,方便后来学习者学习或直接使用。
HttpSession.h
1
#pragma
once
2
3 #include < vector >
4 #include < WinInet.h >
5
6 #define MAXBUFFERSIZE 65535
7
8 #define T_ACCEPT_ENCODING "Accept-Encoding"
9 #define T_CLIENTAGENT "Client-Agent"
10 #define T_CALLINGLINEID "x-up-calling-line-id"
11 #define T_APIVERSION "APIVersion"
12 #define T_USERID "user-id"
13 #define T_ACTION "nAction"
14 #define T_COOKIE "Cookie"
15 #define T_CONTENTTYPE "Content-Type"
16 #define T_CLIENTTYPE "X-ClientType"
17 #define T_CONTENTLEN "Content-Length"
18 #define T_HOST "Host"
19
20 #ifndef FREEIF
21 #define FREEIF(p) {if (p) {delete (p); (p) = NULL;}}
22 #endif
23
24 #ifndef FREEARRAYIF
25 #define FREEARRAYIF(p) {if (p) { delete[] p; (p) = NULL; }}
26 #endif
27
28 void AsyncInternetCallback2(HINTERNET hInternet,
29 DWORD dwContext,
30 DWORD dwInternetStatus,
31 LPVOID lpStatusInfo,
32 DWORD dwStatusInfoLen);
33
34 class CHttpSession
35 {
36 public :
37 CHttpSession();
38 ~ CHttpSession();
39
40 public :
41 // 添加请求头字符串
42 bool SetHeadValue( const char * aKey, const char * aValue );
43
44 bool SetServer( const char * aServer );
45
46 // URL不包含服务器IP和端口号
47 bool SetRequestUrl( const char * aUrl );
48
49 bool SetPort( int aPort );
50
51 // 设置请求数据,仅用于POST请求,GET请求无需使用
52 bool SetRequestData( const char * aData );
53
54 inline const char * GetRecvHead();
55
56 // 获取返回的数据体
57 inline const char * GetRecvieData( );
58
59 // 获取返回数据的长度
60 inline DWORD GetReceivedDataLen();
61
62 // 获取返回码
63 DWORD GetRetCode();
64
65 // 获取返回数据头中的字段的值
66 const char * GetRetHeadValue( char * aKey );
67
68 // 调用doRequest之前,需要将所有数据都准备好
69 bool DoRequest();
70
71 protected :
72 BOOL RetrievingHeaders(HINTERNET hHttp);
73
74 protected :
75 std::vector < char *> m_vtRequestHead; // 请求消息头的字符串
76 char * m_pRequestBody; // 请求的消息体
77 DWORD m_dwRequestBodyLen; // 请求消息体的长度
78
79 char * m_pHost; // 服务器地址
80 int m_pPort; // 端口
81 char * m_pRequestUrl; // 请求URL地址
82
83 char * m_pRecvHead; // 接收到的数据头
84 char * m_pRecvBuf; // 接收的缓存
85 DWORD m_dwRecvBodySize; // 收到数据的总大小
86 DWORD m_dwMaxBuf; // 接收数据缓存的总容器大小
87 DWORD m_dwStartPos; // 当前缓存的偏移,已存放在缓存中的数据长度
88 };
89
2
3 #include < vector >
4 #include < WinInet.h >
5
6 #define MAXBUFFERSIZE 65535
7
8 #define T_ACCEPT_ENCODING "Accept-Encoding"
9 #define T_CLIENTAGENT "Client-Agent"
10 #define T_CALLINGLINEID "x-up-calling-line-id"
11 #define T_APIVERSION "APIVersion"
12 #define T_USERID "user-id"
13 #define T_ACTION "nAction"
14 #define T_COOKIE "Cookie"
15 #define T_CONTENTTYPE "Content-Type"
16 #define T_CLIENTTYPE "X-ClientType"
17 #define T_CONTENTLEN "Content-Length"
18 #define T_HOST "Host"
19
20 #ifndef FREEIF
21 #define FREEIF(p) {if (p) {delete (p); (p) = NULL;}}
22 #endif
23
24 #ifndef FREEARRAYIF
25 #define FREEARRAYIF(p) {if (p) { delete[] p; (p) = NULL; }}
26 #endif
27
28 void AsyncInternetCallback2(HINTERNET hInternet,
29 DWORD dwContext,
30 DWORD dwInternetStatus,
31 LPVOID lpStatusInfo,
32 DWORD dwStatusInfoLen);
33
34 class CHttpSession
35 {
36 public :
37 CHttpSession();
38 ~ CHttpSession();
39
40 public :
41 // 添加请求头字符串
42 bool SetHeadValue( const char * aKey, const char * aValue );
43
44 bool SetServer( const char * aServer );
45
46 // URL不包含服务器IP和端口号
47 bool SetRequestUrl( const char * aUrl );
48
49 bool SetPort( int aPort );
50
51 // 设置请求数据,仅用于POST请求,GET请求无需使用
52 bool SetRequestData( const char * aData );
53
54 inline const char * GetRecvHead();
55
56 // 获取返回的数据体
57 inline const char * GetRecvieData( );
58
59 // 获取返回数据的长度
60 inline DWORD GetReceivedDataLen();
61
62 // 获取返回码
63 DWORD GetRetCode();
64
65 // 获取返回数据头中的字段的值
66 const char * GetRetHeadValue( char * aKey );
67
68 // 调用doRequest之前,需要将所有数据都准备好
69 bool DoRequest();
70
71 protected :
72 BOOL RetrievingHeaders(HINTERNET hHttp);
73
74 protected :
75 std::vector < char *> m_vtRequestHead; // 请求消息头的字符串
76 char * m_pRequestBody; // 请求的消息体
77 DWORD m_dwRequestBodyLen; // 请求消息体的长度
78
79 char * m_pHost; // 服务器地址
80 int m_pPort; // 端口
81 char * m_pRequestUrl; // 请求URL地址
82
83 char * m_pRecvHead; // 接收到的数据头
84 char * m_pRecvBuf; // 接收的缓存
85 DWORD m_dwRecvBodySize; // 收到数据的总大小
86 DWORD m_dwMaxBuf; // 接收数据缓存的总容器大小
87 DWORD m_dwStartPos; // 当前缓存的偏移,已存放在缓存中的数据长度
88 };
89
HttpSession.cpp:
#include "stdafx.h"
#include "HttpSession.h"
#include "Util.h"
#include <wininet.h>
#pragma comment(lib, "Wininet.lib")
HINTERNET hInstance;
HINTERNET hConnect;
HINTERNET hRequest;
HANDLE hConnectedEvent;
HANDLE hRequestOpenedEvent;
HANDLE hRequestCompleteEvent;
BOOL bAllDone ;
extern const char * lpszServer;
extern const char * lpszUrl;
#define CONNECTION_CONTEXT 1
#define REQUEST_CONTEXT 2
#define MAX_BODY_SIZE 10*1024
CHttpSession::CHttpSession()
:m_pRequestBody(NULL),m_pHost(NULL), m_pRequestUrl( NULL ),m_pRecvBuf(NULL),m_pRecvHead(NULL)
,m_dwRecvBodySize(0), m_dwMaxBuf(0) ,m_dwStartPos(0),m_dwRequestBodyLen(0)
{
hConnectedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
hRequestOpenedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
hRequestCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}
CHttpSession::~CHttpSession()
{
FREEARRAYIF( m_pRequestBody );
FREEARRAYIF( m_pHost );
FREEARRAYIF( m_pRequestUrl );
FREEARRAYIF( m_pRecvBuf );
FREEARRAYIF( m_pRecvHead );
}
bool CHttpSession::SetHeadValue( const char* aKey, const char* aValue )
{
if ( !aKey )
return false;
char* buf = new char[256];
memset( buf, 0, 256 );
sprintf( buf, "%s: %s\r\n", aKey, aValue );
m_vtRequestHead.push_back( buf );
return true;
}
bool CHttpSession::SetRequestData( const char* aData )
{
if( !aData )
return false;
m_pRequestBody = new char[strlen( aData ) + 1];
memset( m_pRequestBody, 0, strlen( aData ) + 1 );
memcpy( m_pRequestBody, aData, strlen( aData ) );
return true;
}
bool CHttpSession::SetServer( const char* aServer )
{
if( !aServer )
return false;
m_pHost = new char[strlen( aServer ) + 1 ];
memset( m_pHost, 0, strlen( aServer ) + 1 );
memcpy( m_pHost, aServer, strlen( aServer ) );
return true;
}
bool CHttpSession::SetRequestUrl( const char* aUrl )
{
if( !aUrl )
return false;
m_pRequestUrl = new char[strlen( aUrl ) + 1 ] ;
memset( m_pRequestUrl, 0, strlen( aUrl ) + 1 );
memcpy( m_pRequestUrl, aUrl, strlen( aUrl ) );
return true;
}
bool CHttpSession::SetPort( int aPort )
{
if ( aPort < 0 )
{
return false;
}
m_pPort = aPort;
return true;
}
bool CHttpSession::DoRequest()
{
//异步
hInstance = InternetOpenA( "TYYD_Mobile_6_0_240_320_E806_C_GG_1_0_0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC); // ASYNC Flag
if( !hInstance ) //有些手机用上面的参数访问不了Internet
hInstance=InternetOpenA("TYYD_Mobile_6_0_240_320_E806_C_GG_1_0_0",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,INTERNET_FLAG_ASYNC);
if ( !hInstance )
{
TraceLog( L"InternetOpen failed, error : %d \r\n",GetLastError() );
return false;
}
TraceLog( L"InternetOpen suceess :%d \r\n",GetLastError() );
// Setup callback function
if (InternetSetStatusCallbackA(hInstance,(INTERNET_STATUS_CALLBACK)&AsyncInternetCallback2) == INTERNET_INVALID_STATUS_CALLBACK)
{
TraceLog( L"InternetSetStatusCallback failed, error : %d \r\n",GetLastError() );
return false;
}
TraceLog( L"InternetSetStatusCallback suceess :%d \r\n",GetLastError() );
// First call that will actually complete asynchronously even
// though there is no network traffic
hConnect = InternetConnectA(hInstance,m_pHost, m_pPort,NULL,NULL,INTERNET_SERVICE_HTTP,0,1); // Connection handle's Context
if (hConnect == NULL)
{
TraceLog( L"hConnect == NULL, errno = %d \r\n ",GetLastError() );
if (GetLastError() != ERROR_IO_PENDING)
{
TraceLog( L"InternetConnect failed, error %d ",GetLastError() );
return false;
}
}
// Wait until we get the connection handle
WaitForSingleObject(hConnectedEvent, INFINITE);
TraceLog( L"Ready To openRequest \r\n");
char* pVerb = !m_pRequestBody ? "GET" : " POST" ;
const char * lpszUrl = "/portalapi/imagedownload?key=1000002845492.jpg&type=content";
// Open the request
hRequest = HttpOpenRequestA(hConnect,
pVerb,
m_pRequestUrl,
NULL, // HTTP version ,If this parameter is NULL, the function uses HTTP/1.1 as the version
NULL, // Reference
NULL,// A pointer to a null-terminated array of strings that indicates media types accepted by the client.
INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,
2); // Request handle's context
if (hRequest == NULL)
{
if (GetLastError() != ERROR_IO_PENDING)
{
TraceLog( L"HttpOpenRequest failed, error = %d \r\n", GetLastError() );
return false;
}
}
// Wait until we get the request handle
WaitForSingleObject(hRequestOpenedEvent, INFINITE);
TraceLog( L"HttpOpenRequest Sucess\r\n" );
//Add Request HeadInfo
for( int i = 0 ; i < m_vtRequestHead.size(); i++ )
{
char* pItem = m_vtRequestHead[i];
HttpAddRequestHeadersA(hRequest, pItem, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE );
}
int nRequestBody = !m_pRequestBody ? 0 : strlen( m_pRequestBody );
// Sends the specified request to the HTTP server.
if (!HttpSendRequestA(hRequest,
NULL, // Pointer to a null-terminated string that contains the additional headers to be appended to the request.
0, // Size of the additional headers
m_pRequestBody, // Pointer to a buffer containing any optional data to be sent immediately after the request headers.
m_dwRequestBodyLen )) // Size of the optional data, in bytes.
{
if (GetLastError() != ERROR_IO_PENDING)
{
TraceLog( L"HttpSendRequest failed, error = %d \r\n", GetLastError() );
return false;
}
}
TraceLog( L"HttpSendRequest Sucess \r\n" );
WaitForSingleObject(hRequestCompleteEvent, INFINITE);
TraceLog( L"------------------- Read the response -------------------\r\n" );
//获取响应数据包头
RetrievingHeaders( hRequest );
DWORD dwLen = 0;
InternetQueryDataAvailable(hRequest,&dwLen,0,0);
char* lpReadBuff = new char[MAX_BODY_SIZE];
do
{
memset(lpReadBuff, 0, MAX_BODY_SIZE);
INTERNET_BUFFERSA InetBuff;
FillMemory(&InetBuff, sizeof(InetBuff), 0);
InetBuff.dwStructSize = sizeof(InetBuff);
InetBuff.lpvBuffer = (LPVOID)lpReadBuff;
InetBuff.dwBufferLength = MAX_BODY_SIZE - 1;
TraceLog( L"Calling InternetReadFileExA \r\n" );
if ( !InternetReadFileExA(hRequest,&InetBuff,IRF_ASYNC, 2) )
{
if (GetLastError() == ERROR_IO_PENDING)
{
TraceLog( L"Waiting for InternetReadFileEx to complete \r\n" );
WaitForSingleObject(hRequestCompleteEvent, INFINITE);
}
else
{
TraceLog( L"InternetReadFileEx failed, error :%d \r\n", GetLastError() );
return false;
}
}
TraceLog( L"InternetReadFileEx success! ReadBufLen = %d \r\n", InetBuff.dwBufferLength );
if (InetBuff.dwBufferLength == 0)
{
TraceLog( L"RecvBuf Complete \r\n");
bAllDone = TRUE;
FILE *file;
file = fopen( "\\a1.jpg", "wb" );
int nwrite;
if ( file )
{
nwrite = fwrite( m_pRecvBuf, 1, m_dwRecvBodySize, file);
}
fclose(file);
}
else
{
m_dwRecvBodySize += InetBuff.dwBufferLength;
if ( !m_pRecvBuf )
{
m_pRecvBuf = new char[MAX_BODY_SIZE];
memset( m_pRecvBuf, 0, MAX_BODY_SIZE );
m_dwMaxBuf = MAX_BODY_SIZE;
}
//剩余空间不足,重新分配空间
if ( m_dwMaxBuf - m_dwStartPos < InetBuff.dwBufferLength + 1)
{
TraceLog( L" Memspace is not enough!" );
char* pTempBuf = m_pRecvBuf;
m_pRecvBuf = new char[m_dwMaxBuf + MAX_BODY_SIZE];
memset( m_pRecvBuf, 0, m_dwMaxBuf + MAX_BODY_SIZE);
m_dwMaxBuf = m_dwMaxBuf + MAX_BODY_SIZE;
memcpy( m_pRecvBuf, pTempBuf, m_dwStartPos);
delete[] pTempBuf;
pTempBuf = NULL;
}
TraceLog( L" Memspace is enough!" );
memcpy( m_pRecvBuf + m_dwStartPos, lpReadBuff, InetBuff.dwBufferLength );
TraceLog( L"InternetReadFileEx startPos = %d, curRecvLen = %d, totalSize = %d! \r\n", m_dwStartPos, InetBuff.dwBufferLength , m_dwRecvBodySize);
m_dwStartPos += InetBuff.dwBufferLength;
}
} while (bAllDone == FALSE);
FREEARRAYIF( lpReadBuff );
return true;
}
BOOL CHttpSession::RetrievingHeaders(HINTERNET hHttp)
{
//LPVOID lpOutBuffer=NULL;
DWORD dwSize = 0;
FREEARRAYIF( m_pRecvHead );
retry:
// This call will fail on the first pass, because no buffer is allocated.
if(!HttpQueryInfo(
hHttp,
HTTP_QUERY_RAW_HEADERS_CRLF,
(LPVOID)m_pRecvHead,
&dwSize,
NULL))
{
if (GetLastError()==ERROR_HTTP_HEADER_NOT_FOUND)
{
TraceLog( L"HttpQueryInfo error : ERROR_HTTP_HEADER_NOT_FOUND \r\n" );
// Code to handle the case where the header isn't available.
return TRUE;
}
else
{
// Check for an insufficient buffer.
if ( GetLastError()==ERROR_INSUFFICIENT_BUFFER )
{
TraceLog( L"HttpQueryInfo error : ERROR_HTTP_HEADER_NOT_FOUND \r\n" );
m_pRecvHead = new char[dwSize];
// Retry the call.
goto retry;
}
else
{
TraceLog( L"HttpQueryInfo error : %d \r\n", GetLastError() );
// Error handling code.
if (m_pRecvHead)
{
delete [] m_pRecvHead;
}
return FALSE;
}
}
}
TraceLog( L"HttpQueryInfo sucess lpOutBuffer = %s\r\n", m_pRecvHead);
return TRUE;
}
DWORD CHttpSession::GetRecvieData()
{
return m_pRecvBuf;
}
const char* CHttpSession::GetRecvHead()
{
return m_pRecvHead;
}
DWORD CHttpSession::GetReceivedDataLen()
{
return m_dwRequestBodyLen;
}
void AsyncInternetCallback2(HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpStatusInfo,
DWORD dwStatusInfoLen)
{
TraceLog( L"dwContext = %d, dwInternetStatus = %d \r\n", dwContext, dwInternetStatus );
switch(dwContext)
{
case 1: // Connection handle
if (dwInternetStatus == INTERNET_STATUS_HANDLE_CREATED)
{
INTERNET_ASYNC_RESULT *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
hConnect = (HINTERNET)pRes->dwResult;
TraceLog( L"Connect handle created \r\n");
SetEvent(hConnectedEvent);
}
break;
case 2: // Request handle
switch(dwInternetStatus)
{
case INTERNET_STATUS_HANDLE_CREATED:
{
INTERNET_ASYNC_RESULT *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
hRequest = (HINTERNET)pRes->dwResult;
TraceLog( L"Request handle created \r\n");
SetEvent(hRequestOpenedEvent);
}
break;
case INTERNET_STATUS_REQUEST_SENT:
{
DWORD *lpBytesSent = (DWORD*)lpStatusInfo;
TraceLog( L"Bytes Sent:%d \r\n", lpBytesSent );
}
break;
case INTERNET_STATUS_REQUEST_COMPLETE:
{
INTERNET_ASYNC_RESULT *pAsyncRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
TraceLog( L"Function call finished, dwResult: %d, dwError: \r\n", pAsyncRes->dwResult, pAsyncRes->dwError);
SetEvent(hRequestCompleteEvent);
}
break;
case INTERNET_STATUS_RECEIVING_RESPONSE:
TraceLog( L"Receiving Response \r\n" );
break;
case INTERNET_STATUS_RESPONSE_RECEIVED:
{
DWORD *dwBytesReceived = (DWORD*)lpStatusInfo;
if (*dwBytesReceived == 0)
bAllDone = TRUE;
TraceLog( L"Receiving %d \r\n", dwBytesReceived);
}
}
break;
default:break;
}
}
测试环境:vs2008 + windows mobile 2003
测试代码:
CHttpSession* pSession = new CHttpSession();
pSession->SetServer( lpszServer );
pSession->SetPort( 8080 );
pSession->SetRequestUrl( lpszUrl );
pSession->SetRequestData( NULL );
pSession->SetHeadValue( T_ACCEPT_ENCODING, "gzip" );
pSession->SetHeadValue( T_CLIENTAGENT, "TYYD_Mobile_6_0_240_320_E806_C_GG_1_0_0" );
pSession->SetHeadValue( T_CALLINGLINEID, "18912345677" );
pSession->SetHeadValue( T_APIVERSION, "1.0.0" );
pSession->SetHeadValue( T_CONTENTTYPE, "application/xml" );
pSession->SetHeadValue( T_CLIENTTYPE, "1");
pSession->SetHeadValue( T_USERID, "" );
pSession->SetHeadValue( T_COOKIE, "" );
pSession->SetHeadValue( T_ACTION, "" );
pSession->DoRequest();