参照MS的例子, 封装了一个异步HttpPost的类, 用起来很简单
异步HttpPost的好处是 : 不会在Win32Api中阻塞住, 程序退出时,速度快.
异步HttpPost主要解决的是程序退出的问题,如果不需要频繁退出的程序,可以使用同步HttpPost操作, 方便易用.
编译环境 : vs2010 vc++ + win32 console
工程下载点: srcAsyncHttpPost_2014_1221_1746.rar
测试程序:
/// @file srcAsyncHttpPost.cpp
/// @brief 参照MS的例子, 封装了一个异步HttpPost的类, 用起来很简单
/// a class do async http post task
#include "stdafx.h"
#include "./Helper/ThreadManager.h"
#include "./Helper/HttpPostTask.h"
#include "./Helper/StringHelper.h"
int _tmain(int argc, _TCHAR* argv[])
{
BOOL bRc = FALSE;
WCHAR cUserInput = L'\0';
std::string strHttpRecv = "";
CHttpPostTask HttpPostTask;
// http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=stl&rsv_pq=9d21509800016bd9&rsv_t=7c03V4xpJO40vaY1cVToAMgdr1gNzCHJFmFf6AGMKqjBFuP7De7D3qxTA%2Fc&rsv_enter=1&inputT=2977&rsv_sug1=39&rsv_sug3=21&rsv_sug4=514&rsv_sug2=0
std::string strServerToPost = "www.baidu.com";
std::string strPostUrl = "/s";
std::string strPostName = "ie";
std::string strPostContent = "utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=stl&rsv_pq=9d21509800016bd9&rsv_t=7c03V4xpJO40vaY1cVToAMgdr1gNzCHJFmFf6AGMKqjBFuP7De7D3qxTA%2Fc&rsv_enter=1&inputT=2977&rsv_sug1=39&rsv_sug3=21&rsv_sug4=514&rsv_sug2=0";
BOOL bPostDataAsGetType = FALSE;
bRc = HttpPostTask.PostDataToWeb_async_GET_or_POST(
strServerToPost,
strPostUrl,
strPostName,
strPostContent,
bPostDataAsGetType);
if (!bRc)
{
_tprintf(L"failed HttpPostTask.PostDataToWeb_async_GET_or_POST\r\n");
}
_tprintf(L"if want stop http post task, press key 'q' or 'Q', then press ENTER key\r\n");
do
{
Sleep(0);
/// 实际的应用中,任务中止的动作是程序退出时发送的 或 自定义超时逻辑发出的
cUserInput = getwchar();
if ((L'q' == cUserInput)
|| (L'Q' == cUserInput))
{
_tprintf(L"user send quit command\r\n");
getwchar(); ///< recive the ENTER key
break;
}
/// @todo 实际工程中,不用轮询任务是否完成
/// 让 HttpPostTask 和 CHttpPostAsync 等待退出和任务完成事件之一
/// 这里轮询,是为了Demo写的简明些
/// 给HttpPostTask增加一个Stop方法, 在另外一个线程中调用, 用于停止HttpPost任务
/// 给HttpPostTask增加一个waitTaskEnd方法, 阻塞等待完成(成功,失败),退出事件之一,
/// 在 PostDataToWeb_async_GET_or_POST 之后阻塞调用
if (HttpPostTask.IsTaskOver())
{
_tprintf(L"ok, HttpPostTask is over\r\n");
break;
}
else
{
_tprintf(L"HttpPostTask is running, if need quit, press q or Q key to quit\r\n");
}
} while (1);
if (HttpPostTask.IsTaskOver())
{
strHttpRecv = HttpPostTask.GetRecv();
strHttpRecv = ns_base::UTF8ToGBK(strHttpRecv);
printf("HttpPostTask.GetErr() = %d\r\nstrHttpRecv = %s\r\n",
HttpPostTask.GetErr(),
strHttpRecv.c_str());
}
_tprintf(L"END, press any key to quit\r\n");
getwchar();
return 0;
}
HttpPost任务类 .h
/// @file HttpPostTask.h
/// @brief HttpPost任务类, 调用HttpPostAsync干活
#ifndef __HTTP_POST_TASK_H__
#define __HTTP_POST_TASK_H__
#include "HttpPostAsync.h"
class CHttpPostTask
{
public:
CHttpPostTask();
virtual ~CHttpPostTask();
BOOL PostDataToWeb_async_GET_or_POST(
IN std::string& strServerToPost,
IN std::string& strPostUrl,
IN std::string& strPostName,
IN std::string& strPostContent,
IN BOOL bPostDataAsGetType);
BOOL IsTaskOver();
CHttpPostAsync::eHttpError GetErr() {return m_httpPostAsync.GetErr();}
std::string GetRecv();
static UINT WINAPI ThreadProc_HttpPost(void* pParam);
UINT ThreadProc_HttpPost();
private:
void DataInit();
private:
CHttpPostAsync m_httpPostAsync;
std::string m_strServerToPost;
std::string m_strPostUrl;
std::string m_strPostName;
std::string m_strPostContent;
BOOL m_bPostDataAsGetType;
std::string m_strRecv;
};
#endif // #ifndef __HTTP_POST_TASK_H__
HttpPost实现类
/// @file HttpPostAsync.h
/// @brief 异步HttpPost类
#ifndef __HTTP_POST_EX_H__
#define __HTTP_POST_EX_H__
#include "EventManager.h"
#include "ThreadManager.h"
typedef struct _tag_cbContext_HttpPostEx TAG_CB_CONTEXT_HTTP_POST_EX;
class CHttpPostAsync
{
public:
CHttpPostAsync();
virtual ~CHttpPostAsync();
public:
enum eHttpContext
{
eHttpCtx_unknown = -1, // 不处理的回调状态
eHttpCtx_Connection, // 以下是需要处理的回调状态
eHttpCtx_OpenRequest,
eHttpCtx_SendRequestHeader,
eHttpCtx_SendRequestHeaderData,
eHttpCtx_GetRemoteResponse,
};
enum eHttpError
{
eHttpError_unknown = -1,
eHttpError_no, ///< 没有错误
eHttpError_CreateWorkerThread,
eHttpError_Param,
eHttpError_InternetOpen,
eHttpError_SetCallBack,
eHttpError_SendRequestHeader,
eHttpError_InternetReadFileEx,
eHttpError_HttpEndRequest,
eHttpError_InternetWriteFile,
eHttpError_InternetConnect,
eHttpError_HttpOpenRequest,
};
public:
void SetErr(eHttpError err) {m_HttpError = err;}
CHttpPostAsync::eHttpError GetErr() {return m_HttpError;}
BOOL PostUrl(const char* pcServerName, const char* pcUrl, const char* pcPostText);
BOOL GetRecvData(std::string& strRecv);
BOOL IsTaskEnd();
BOOL Stop();
void SetNeedStop(BOOL bNeedStop)
{
m_bCmdStop = bNeedStop;
m_Event_CmdStop.SetEvent();
}
BOOL IsNeedStop() {return m_bCmdStop;}
static UINT WINAPI ThreadProc_HttpPostAsync(void* pParam);
UINT ThreadProc_HttpPostAsync();
void __stdcall CallbackProc_HttpPostEx_Connection(HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpStatusInfo,
DWORD dwStatusInfoLen);
void __stdcall CallbackProc_HttpPostEx_OpenRequest(HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpStatusInfo,
DWORD dwStatusInfoLen);
void __stdcall CallbackProc_HttpPostEx_SendRequestHeader(HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpStatusInfo,
DWORD dwStatusInfoLen);
void __stdcall CallbackProc_HttpPostEx_GetRemoteResponse(HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpStatusInfo,
DWORD dwStatusInfoLen);
private:
void DataInit();
BOOL CreateWorkerThread();
BOOL DoInternetOpen(HINTERNET& hSession);
BOOL DoSetCallback(HINTERNET& hHandle, INTERNET_STATUS_CALLBACK pcbfn);
BOOL DoConnect(HINTERNET& hConnect);
BOOL DoOpenRequest();
BOOL DoSendRequest();
BOOL DoGetRemoteResponse();
void DoCloseConnect();
void DoResetAllEventOnWait();
private:
std::string m_strServerName;
std::string m_strUrl;
std::string m_strPostContent;
std::string m_strRecvContent;
ns_base::CThreadManager m_ThreadManager_WorkerThread;
ns_base::CEventManager m_Event_ConnectedOver;
ns_base::CEventManager m_Event_OpenRequestOver;
ns_base::CEventManager m_Event_SendRequestOver;
ns_base::CEventManager m_Event_GetRemoteResponseOver;
ns_base::CEventManager m_Event_CmdStop;
HINTERNET m_hSession;
HINTERNET m_hConnect;
HINTERNET m_hOpenRequest;
BOOL m_bAllDone;
eHttpError m_HttpError; ///< http操作中的错误码
BOOL m_bCmdStop; ///< 外部发出的停止命令
TAG_CB_CONTEXT_HTTP_POST_EX* m_pHttpPostContext;
};
typedef struct _tag_cbContext_HttpPostEx
{
CHttpPostAsync* pOnwer;
CHttpPostAsync::eHttpContext ContextCode;
_tag_cbContext_HttpPostEx()
{
pOnwer = NULL;
ContextCode = CHttpPostAsync::eHttpCtx_unknown;
}
void SetParam(CHttpPostAsync* pOnwer, CHttpPostAsync::eHttpContext ContextCode)
{
this->pOnwer = pOnwer;
this->ContextCode = ContextCode;
}
}TAG_CB_CONTEXT_HTTP_POST_EX;
#endif // #ifndef __HTTP_POST_EX_H__
类实现:
/// @file HttpPostTask.cpp
/// @brief ...
#include "stdafx.h"
#include "constDefine.h"
#include "HttpPostTask.h"
#include "StringHelper.h"
CHttpPostTask::CHttpPostTask()
{
DataInit();
}
CHttpPostTask::~CHttpPostTask()
{
}
void CHttpPostTask::DataInit()
{
m_strServerToPost = "";
m_strPostUrl = "";
m_strPostName = "";
m_strPostContent = "";
m_bPostDataAsGetType = FALSE;
m_strRecv = "";
}
BOOL CHttpPostTask::PostDataToWeb_async_GET_or_POST(
IN std::string& strServerToPost,
IN std::string& strPostUrl,
IN std::string& strPostName,
IN std::string& strPostContent,
IN BOOL bPostDataAsGetType)
{
USES_CONVERSION;
BOOL bRc = FALSE;
std::string strPostUrlIn = "";
std::string strPostTextIn = "";
std::string strPostUrlInUtf8 = "";
std::string strPostTextInUtf8 = "";
m_strServerToPost = strServerToPost;
m_strPostUrl = strPostUrl;
m_strPostName = strPostName;
m_strPostContent = strPostContent;
m_bPostDataAsGetType = bPostDataAsGetType;
m_strRecv = "";
strPostUrlIn = strPostUrl.c_str();
strPostTextIn = ns_base::StringFormatVA("%s=%s",
strPostName.c_str(),
strPostContent.c_str());
if (bPostDataAsGetType)
{
strPostUrlIn += "&";
strPostUrlIn += strPostTextIn.c_str();
strPostTextIn = "";
}
// if strPostUrlIn or strPostTextIn include chinese word, need convert to utf8
// then call http post
strPostUrlIn = ns_base::GBK2UTF8(strPostUrlIn);
strPostTextIn = ns_base::GBK2UTF8(strPostTextIn);
return m_httpPostAsync.PostUrl(strServerToPost.c_str(), strPostUrlIn.c_str(), strPostTextIn.c_str());
}
BOOL CHttpPostTask::IsTaskOver()
{
return m_httpPostAsync.IsTaskEnd();
}
UINT WINAPI CHttpPostTask::ThreadProc_HttpPost(void* pParam)
{
if (NULL == pParam)
return S_FALSE;
return ((CHttpPostTask*)pParam)->ThreadProc_HttpPost();
}
UINT CHttpPostTask::ThreadProc_HttpPost()
{
return S_OK;
}
std::string CHttpPostTask::GetRecv()
{
m_httpPostAsync.GetRecvData(m_strRecv);
return m_strRecv;
}
/// @file HttpPostAsync.cpp
/// @brief ...
#include <stdafx.h>
#include "constDefine.h"
#include "HttpPostAsync.h"
void __stdcall Callback_HttpPostEx(
HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpStatusInfo,
DWORD dwStatusInfoLen)
{
TAG_CB_CONTEXT_HTTP_POST_EX* pcbContext = (TAG_CB_CONTEXT_HTTP_POST_EX*)dwContext;
if (NULL == pcbContext)
return;
if (NULL == pcbContext->pOnwer)
return;
switch (pcbContext->ContextCode)
{
case CHttpPostAsync::eHttpCtx_Connection:
{
pcbContext->pOnwer->CallbackProc_HttpPostEx_Connection(
hInternet,
dwContext,
dwInternetStatus,
lpStatusInfo,
dwStatusInfoLen);
}
break;
case CHttpPostAsync::eHttpCtx_OpenRequest:
{
pcbContext->pOnwer->CallbackProc_HttpPostEx_OpenRequest(
hInternet,
dwContext,
dwInternetStatus,
lpStatusInfo,
dwStatusInfoLen);
}
break;
case CHttpPostAsync::eHttpCtx_SendRequestHeader:
{
pcbContext->pOnwer->CallbackProc_HttpPostEx_SendRequestHeader(
hInternet,
dwContext,
dwInternetStatus,
lpStatusInfo,
dwStatusInfoLen);
}
break;
case CHttpPostAsync::eHttpCtx_GetRemoteResponse:
{
pcbContext->pOnwer->CallbackProc_HttpPostEx_GetRemoteResponse(
hInternet,
dwContext,
dwInternetStatus,
lpStatusInfo,
dwStatusInfoLen);
}
break;
case CHttpPostAsync::eHttpCtx_unknown:
default:
{
/// SendRequest没有指定回调时,会进这里. 不能做任何处理
/// pcbContext->pOnwer是无效的
}
break;
}
}
void __stdcall CHttpPostAsync::CallbackProc_HttpPostEx_Connection(
HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpStatusInfo,
DWORD dwStatusInfoLen)
{
if (IsNeedStop())
return;
switch (dwInternetStatus)
{
case INTERNET_STATUS_HANDLE_CREATED:
{
m_Event_ConnectedOver.SetEvent();
}
break;
default:
break;
}
}
void __stdcall CHttpPostAsync::CallbackProc_HttpPostEx_OpenRequest(
HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpStatusInfo,
DWORD dwStatusInfoLen)
{
if (IsNeedStop())
return;
switch (dwInternetStatus)
{
case INTERNET_STATUS_HANDLE_CREATED:
{
m_Event_OpenRequestOver.SetEvent();
}
break;
default:
break;
}
}
void __stdcall CHttpPostAsync::CallbackProc_HttpPostEx_SendRequestHeader(
HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpStatusInfo,
DWORD dwStatusInfoLen)
{
if (IsNeedStop())
return;
switch (dwInternetStatus)
{
case INTERNET_STATUS_REQUEST_COMPLETE:
{
m_Event_SendRequestOver.SetEvent();
}
break;
default:
break;
}
}
void __stdcall CHttpPostAsync::CallbackProc_HttpPostEx_GetRemoteResponse(
HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpStatusInfo,
DWORD dwStatusInfoLen)
{
if (IsNeedStop())
return;
switch (dwInternetStatus)
{
case INTERNET_STATUS_REQUEST_COMPLETE:
{
m_Event_GetRemoteResponseOver.SetEvent();
}
break;
default:
break;
}
}
CHttpPostAsync::CHttpPostAsync()
{
DataInit();
}
CHttpPostAsync::~CHttpPostAsync()
{
SAFE_DELETE(m_pHttpPostContext);
}
void CHttpPostAsync::DataInit()
{
m_strServerName = "";
m_strUrl = "";
m_strPostContent = "";
m_strRecvContent = "";
m_hSession = NULL;
m_hConnect = NULL;
m_hOpenRequest = NULL;
m_bAllDone = FALSE;
SetErr(eHttpError_no); ///< 初始为没有错误
SetNeedStop(FALSE);
m_pHttpPostContext = new TAG_CB_CONTEXT_HTTP_POST_EX;
}
void CHttpPostAsync::DoCloseConnect()
{
/// @todo SAFE_CLOSE_HANDLE 会报错, 不用关闭么?
DoSetCallback(m_hSession, NULL);
SAFE_CLOSE_HINTERNET(m_hOpenRequest);
SAFE_CLOSE_HINTERNET(m_hConnect);
SAFE_CLOSE_HINTERNET(m_hSession);
}
void CHttpPostAsync::DoResetAllEventOnWait()
{
SetNeedStop(FALSE);
SetErr(eHttpError_no);
m_Event_ConnectedOver.ResetEvent();
m_Event_OpenRequestOver.ResetEvent();
m_Event_SendRequestOver.ResetEvent();
m_Event_GetRemoteResponseOver.ResetEvent();
m_Event_CmdStop.ResetEvent();
}
BOOL CHttpPostAsync::PostUrl(const char* pcServerName, const char* pcUrl, const char* pcPostText)
{
BOOL bRc = FALSE;
do
{
if ((NULL == pcServerName))
break;
m_strServerName = pcServerName;
if (NULL == pcUrl)
break;
m_strUrl = pcUrl;
m_strPostContent = (NULL == pcPostText) ? "" : pcPostText;
/// 起一条线程, 执行异步http post任务
if (!CreateWorkerThread())
break;
bRc = TRUE;
} while (0);
if (!bRc)
{
SetErr(eHttpError_CreateWorkerThread);
}
return bRc;
}
BOOL CHttpPostAsync::CreateWorkerThread()
{
if (!m_ThreadManager_WorkerThread.IsNeedQuitThread()
&& !m_ThreadManager_WorkerThread.IsThreadRunning())
{
DoCloseConnect();
DoResetAllEventOnWait();
m_ThreadManager_WorkerThread.SetThreadHandle(
(HANDLE)_beginthreadex(
NULL,
0,
&CHttpPostAsync::ThreadProc_HttpPostAsync,
(void*)this,
0,
NULL));
}
return TRUE;
}
UINT WINAPI CHttpPostAsync::ThreadProc_HttpPostAsync(void* pParam)
{
UINT uRc = S_FALSE;
CHttpPostAsync* pMe = NULL;
do
{
if (NULL == pParam)
{
pMe->SetErr(eHttpError_Param);
break;
}
pMe = (CHttpPostAsync*)pParam;
uRc = pMe->ThreadProc_HttpPostAsync();
} while (0);
return uRc;
}
BOOL CHttpPostAsync::DoInternetOpen(HINTERNET& hSession)
{
BOOL bRc = FALSE;
DWORD dwErr = 0;
const char* pcAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.8888.8888;)";
do
{
if (IsNeedStop())
break;
hSession = InternetOpenA(pcAgent,
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
INTERNET_FLAG_ASYNC); // ASYNC Flag
if (NULL == hSession)
{
SetErr(eHttpError_InternetOpen);
break;
}
if (!DoSetCallback(hSession, &Callback_HttpPostEx))
break;
bRc = TRUE;
} while (0);
return bRc;
}
BOOL CHttpPostAsync::DoSetCallback(HINTERNET& hHandle, INTERNET_STATUS_CALLBACK pcbfn)
{
BOOL bRc = FALSE;
DWORD dwErr = 0;
INTERNET_STATUS_CALLBACK status = INTERNET_INVALID_STATUS_CALLBACK;
do
{
if (IsNeedStop())
break;
if ((NULL == hHandle) || (INVALID_HANDLE_VALUE == hHandle))
break;
status = InternetSetStatusCallback(
hHandle,
(INTERNET_STATUS_CALLBACK)pcbfn);
if (INTERNET_INVALID_STATUS_CALLBACK == status)
{
SetErr(eHttpError_SetCallBack);
break;
}
bRc = TRUE;
} while (0);
return bRc;
}
BOOL CHttpPostAsync::DoConnect(HINTERNET& hConnect)
{
BOOL bRc = FALSE;
DWORD dwErr = 0;
HANDLE ArrEvent[2];
ArrEvent[0] = m_Event_CmdStop.GetHandle();
ArrEvent[1] = m_Event_ConnectedOver.GetHandle();
do
{
if (IsNeedStop())
break;
m_pHttpPostContext->SetParam(this, eHttpCtx_Connection);
m_hConnect = InternetConnectA(
m_hSession,
m_strServerName.c_str(),
INTERNET_DEFAULT_HTTP_PORT,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
(DWORD_PTR)(m_pHttpPostContext));
if (NULL == m_hConnect)
{
dwErr = ::GetLastError();
if (ERROR_IO_PENDING != dwErr)
{
SetErr(eHttpError_InternetConnect);
break;
}
WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
}
bRc = TRUE;
} while (0);
m_Event_ConnectedOver.ResetEvent();
return bRc;
}
BOOL CHttpPostAsync::DoOpenRequest()
{
BOOL bRc = FALSE;
DWORD dwErr = 0;
char* szAccept[] = {"Accept: */*", NULL}; //接受文件的类型
HANDLE ArrEvent[2];
ArrEvent[0] = m_Event_CmdStop.GetHandle();
ArrEvent[1] = m_Event_OpenRequestOver.GetHandle();
do
{
if (IsNeedStop())
break;
m_pHttpPostContext->SetParam(this, eHttpCtx_OpenRequest);
m_hOpenRequest = HttpOpenRequestA(
m_hConnect,
"POST",
m_strUrl.c_str(),
"HTTP/1.1",
NULL,
(LPCSTR *)&szAccept,
INTERNET_FLAG_RELOAD,
(DWORD_PTR)(m_pHttpPostContext));
if (NULL == m_hOpenRequest)
{
if (GetLastError() != ERROR_IO_PENDING)
{
SetErr(eHttpError_HttpOpenRequest);
dwErr = ::GetLastError();
break;
}
WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
}
if (!DoSetCallback(m_hOpenRequest, &Callback_HttpPostEx))
break;
bRc = TRUE;
} while (0);
m_Event_OpenRequestOver.ResetEvent();
return bRc;
}
BOOL CHttpPostAsync::DoSendRequest()
{
BOOL bRc = FALSE;
DWORD dwErr = 0;
char strHeaders[] = "Content-Type: application/x-www-form-urlencoded\r\n";
INTERNET_BUFFERSA InetBuff;
HANDLE ArrEvent[2];
DWORD dwBytesWritten = 0;
ArrEvent[0] = m_Event_CmdStop.GetHandle();
ArrEvent[1] = m_Event_SendRequestOver.GetHandle();
do
{
/// 发送http header
if (IsNeedStop())
break;
m_pHttpPostContext->SetParam(this, eHttpCtx_SendRequestHeader);
FillMemory(&InetBuff, sizeof(InetBuff), 0);
InetBuff.dwStructSize= sizeof(InetBuff);
InetBuff.dwBufferTotal = strlen(m_strPostContent.c_str());
InetBuff.lpcszHeader = strHeaders;
InetBuff.dwHeadersLength = strlen(InetBuff.lpcszHeader);
if (!HttpSendRequestExA(m_hOpenRequest,
&InetBuff,
NULL,
INTERNET_KEEP_ALIVE_DISABLED,
(DWORD_PTR)(m_pHttpPostContext)))
{
if (GetLastError() != ERROR_IO_PENDING)
{
SetErr(eHttpError_SendRequestHeader);
break;
}
WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
}
/// 发送 post's content
if (IsNeedStop())
break;
m_Event_SendRequestOver.ResetEvent(); ///< !
if (strlen(m_strPostContent.c_str()) > 0)
{
/// 如果 InternetWriteFile 0 长度的数据, 会失败的
if(!InternetWriteFile(m_hOpenRequest,
m_strPostContent.c_str(),
strlen(m_strPostContent.c_str()),
&dwBytesWritten))
{
if (GetLastError() != ERROR_IO_PENDING)
{
SetErr(eHttpError_InternetWriteFile);
break;
}
else
{
WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
}
}
m_Event_SendRequestOver.ResetEvent(); ///< !
}
/// end request
if (!HttpEndRequest(m_hOpenRequest, NULL, HSR_INITIATE, (DWORD_PTR)(m_pHttpPostContext)))
{
if (GetLastError() == ERROR_IO_PENDING)
{
WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
}
else
{
SetErr(eHttpError_HttpEndRequest);
break;
}
}
bRc = TRUE;
} while (0);
m_Event_SendRequestOver.ResetEvent();
return bRc;
}
BOOL CHttpPostAsync::DoGetRemoteResponse()
{
DWORD dwErr = 0;
char szReadBuff[2048];
std::string strRecvOnce = "";
INTERNET_BUFFERS InetBuff;
HANDLE ArrEvent[2];
ArrEvent[0] = m_Event_CmdStop.GetHandle();
ArrEvent[1] = m_Event_GetRemoteResponseOver.GetHandle();
m_strRecvContent = "";
do
{
if (IsNeedStop())
break;
FillMemory(&InetBuff, sizeof(InetBuff), 0);
InetBuff.dwStructSize = sizeof(InetBuff);
InetBuff.lpvBuffer = szReadBuff;
InetBuff.dwBufferLength = sizeof(szReadBuff) - 1;
m_pHttpPostContext->SetParam(this, eHttpCtx_GetRemoteResponse);
if (!InternetReadFileEx(
m_hOpenRequest,
&InetBuff,
IRF_ASYNC,
(DWORD_PTR)(m_pHttpPostContext)))
{
dwErr = ::GetLastError();
if (ERROR_IO_PENDING == dwErr)
{
WaitForMultipleObjects(sizeof(ArrEvent) / sizeof(HANDLE), ArrEvent, FALSE, INFINITE);
m_Event_GetRemoteResponseOver.ResetEvent();
}
else
{
SetErr(eHttpError_InternetReadFileEx);
break;
}
}
if (IsNeedStop())
break;
szReadBuff[InetBuff.dwBufferLength] = 0;
if ((InetBuff.dwBufferLength != 0)
&& (InetBuff.dwBufferLength != (DWORD)(-1)))
{
strRecvOnce.resize(InetBuff.dwBufferLength);
::memcpy((void*)strRecvOnce.data(), szReadBuff, InetBuff.dwBufferLength);
m_strRecvContent.append(strRecvOnce);
}
if (InetBuff.dwBufferLength == 0)
m_bAllDone = TRUE;
} while (!m_bAllDone);
m_Event_GetRemoteResponseOver.ResetEvent();
if (m_bAllDone)
{
if ((m_strRecvContent.size() >= 3)
&& ((UCHAR)0xef == (UCHAR)m_strRecvContent[0])
&& ((UCHAR)0xbb == (UCHAR)m_strRecvContent[1])
&& ((UCHAR)0xbf == (UCHAR)m_strRecvContent[2]))
{
m_strRecvContent.erase(0, 3);
}
}
return m_bAllDone;
}
UINT CHttpPostAsync::ThreadProc_HttpPostAsync()
{
UINT uRc = S_FALSE;
do
{
if (!DoInternetOpen(m_hSession))
break;
if (!DoConnect(m_hConnect))
break;
if (!DoOpenRequest())
break;
if (!DoSendRequest())
break;
if (!DoGetRemoteResponse())
break;
uRc = S_OK;
} while (0);
DoSetCallback(m_hSession, NULL);
return uRc;
}
BOOL CHttpPostAsync::GetRecvData(std::string& strRecv)
{
strRecv = m_strRecvContent;
return TRUE;
}
BOOL CHttpPostAsync::IsTaskEnd()
{
return (m_bAllDone || (eHttpError_no != GetErr()));
}
BOOL CHttpPostAsync::Stop()
{
SetNeedStop(TRUE);
m_ThreadManager_WorkerThread.StopThread(L"m_ThreadManager_WorkerThread");
DoCloseConnect();
return TRUE;
}