#include "stdafx.h" #pragma once ////////////////////////////////// HttpClient.cpp #include "HttpThread.h" #include "AttemperEngineSink.h" #include "ShowTime.h" #include "LogonServer.h" #include "LogonServerDlg.h" #include #include #include "ServiceUnits.h" #include "ChineseCode.h" #include "../Json/json.h" #include "curl/curl.h" #include "../../../Games/Normal/松滋晃晃血流/消息定义/CMD_Sparrow.h" #define BUFFER_SIZE 1024 #define NORMAL_CONNECT INTERNET_FLAG_KEEP_CONNECTION #define SECURE_CONNECT NORMAL_CONNECT | INTERNET_FLAG_SECURE #define NORMAL_REQUEST INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE #define SECURE_REQUEST NORMAL_REQUEST | INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID HANDLE CHttpClient::m_hThread = nullptr; unsigned CHttpClient::m_uiThreadID = 0; HANDLE CHttpClient::g_Event; // 触发事件句柄 CAttemperEngineSink* CHttpClient::pCAttemperEngineSink = NULL; //调度钩子 bool CHttpClient::m_bRun = true;// 关闭 std::unordered_map CHttpClient::GetData; CCriticalSection CHttpClient::m_CriticalSection; extern CLogonServerApp theApp; void* CHttpClient::curl = NULL; CHttpClient::CHttpClient(LPCTSTR strAgent) : m_bDebug(false) { m_pSession = new CInternetSession(strAgent); INTERNET_PROXY_INFO ipi; ZeroMemory(&ipi, sizeof(ipi)); ipi.dwAccessType = INTERNET_OPEN_TYPE_DIRECT; ipi.lpszProxyBypass = NULL; m_pSession->SetOption(INTERNET_OPEN_TYPE_DIRECT, &ipi, sizeof(ipi), 0); m_pConnection = NULL; m_pFile = NULL; } CHttpClient::~CHttpClient(void) { Clear(); if (NULL != m_pSession) { m_pSession->Close(); delete m_pSession; m_pSession = NULL; } } void CHttpClient::Clear() { if (NULL != m_pFile) { m_pFile->Close(); delete m_pFile; m_pFile = NULL; } if (NULL != m_pConnection) { m_pConnection->Close(); delete m_pConnection; m_pConnection = NULL; } } int CHttpClient::ExecuteRequest(LPCTSTR strMethod, LPCTSTR strUrl, LPCTSTR strPostData, CString &strResponse, CString &Err) { CString strServer; CString strObject; DWORD dwServiceType; INTERNET_PORT nPort; strResponse = ""; Err = ""; AfxParseURL(strUrl, dwServiceType, strServer, strObject, nPort); if (AFX_INET_SERVICE_HTTP != dwServiceType && AFX_INET_SERVICE_HTTPS != dwServiceType) { return FAILURE; } try { m_pConnection = m_pSession->GetHttpConnection(strServer, dwServiceType == AFX_INET_SERVICE_HTTP ? NORMAL_CONNECT : SECURE_CONNECT, nPort); m_pFile = m_pConnection->OpenRequest(strMethod, strObject, NULL, 1, NULL, NULL, (dwServiceType == AFX_INET_SERVICE_HTTP ? NORMAL_REQUEST : SECURE_REQUEST)); //DWORD dwFlags; //m_pFile->QueryOption(INTERNET_OPTION_SECURITY_FLAGS, dwFlags); //dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; ////set web server option //m_pFile->SetOption(INTERNET_OPTION_SECURITY_FLAGS, dwFlags); m_pFile->AddRequestHeaders(_T("Accept: *,*/*")); m_pFile->AddRequestHeaders(_T("Accept-Language: zh-cn")); m_pFile->AddRequestHeaders(_T("Content-Type: application/x-www-form-urlencoded")); m_pFile->AddRequestHeaders(_T("Accept-Encoding: gzip, deflate")); m_pFile->SendRequest(NULL, 0, (LPVOID)(LPCTSTR)strPostData, strPostData == NULL ? 0 : _tcslen(strPostData)); char szChars[BUFFER_SIZE + 1] = { 0 }; CStringA strRawResponse = ""; UINT nReaded = 0; while ((nReaded = m_pFile->Read((void*)szChars, BUFFER_SIZE)) > 0) { szChars[nReaded] = '\0'; strRawResponse += szChars; memset(szChars, 0, BUFFER_SIZE + 1); } int unicodeLen = MultiByteToWideChar(CP_UTF8, 0, strRawResponse, -1, NULL, 0); WCHAR *pUnicode = new WCHAR[unicodeLen + 1]; memset(pUnicode, 0, (unicodeLen + 1)*sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, strRawResponse, -1, pUnicode, unicodeLen); CString cs(pUnicode); delete[]pUnicode; pUnicode = NULL; strResponse = cs; Clear(); } catch (CInternetException* e) { Clear(); DWORD dwErrorCode = e->m_dwError; e->Delete(); DWORD dwError = GetLastError(); //PRINT_LOG("dwError = %d", dwError, 0); if (ERROR_INTERNET_TIMEOUT == dwErrorCode) { Err.Format(_T("请求超时, LastError=%d"), dwErrorCode); return OUTTIME; } else { Err.Format(_T("请求失败, LastError=%d"), dwErrorCode); return FAILURE; } } return SUCCESS; } int CHttpClient::HttpGet(LPCTSTR strUrl, LPCTSTR strPostData, CString &strResponse, CString &Err) { return ExecuteRequest(_T("GET"), strUrl, strPostData, strResponse, Err); } int CHttpClient::HttpPost(LPCTSTR strUrl, LPCTSTR strPostData, CString &strResponse, CString &Err) { return ExecuteRequest(_T("POST"), strUrl, strPostData, strResponse, Err); } //添加 void CHttpClient::AddLog(DWORD dwSocketID, GETDUILIEBASE_EX LogText) { CWHDataLocker lock(m_CriticalSection); if (!m_bRun) return; if (GetData.find(dwSocketID) == GetData.end()) { GETDUILIEBASE_EX_LIST mData; ZeroMemory(&mData, sizeof(mData)); mData.dDataList[0] = LogText; std::pair aa(dwSocketID, mData); GetData.insert(aa); if (pCAttemperEngineSink) { if (LogText.CommendID == 1) { CString csTest; csTest.Format(_T("手机号码(%s)添加了一条获取验证码任务"), LogText.szIphoneNum); CShowTime aa(csTest, true, 99999, 99999); } } if (g_Event) SetEvent(g_Event); } else { std::unordered_map::iterator it = GetData.find(dwSocketID); GETDUILIEBASE_EX_LIST gTemp = it->second; //查询有没有这个命令 for (int i = 0; i < 10; i++) { if (gTemp.dDataList[i].CommendID == 0) continue; //重复命令,只能发送一次 if (gTemp.dDataList[i].CommendID == LogText.CommendID) return; } for (int i = 0; i < 10; i++) { if (gTemp.dDataList[i].CommendID == 0) { gTemp.dDataList[i] = LogText; GetData[dwSocketID] = gTemp; break; } } if (LogText.CommendID == 1) { CString csTest; csTest.Format(_T("玩家(%d)添加了大于一条任务->%s"), LogText.CommendID, _T("请求订单")); CShowTime aa(csTest, true, 99999, 99999); } if (g_Event) SetEvent(g_Event); } } //获取 std::unordered_map CHttpClient::GetLog() { CWHDataLocker lock(m_CriticalSection);// std::unordered_map Ret = GetData; GetData.clear(); return Ret; } //获取数量 DWORD CHttpClient::GetCount() { CWHDataLocker lock(m_CriticalSection); return GetData.size(); } //启动 bool CHttpClient::start(CAttemperEngineSink* pSink) { if (m_hThread != NULL) return false; CString csEvent; //随机种子 srand(GetTickCount()); int iRand = rand()%9999; csEvent.Format(_T("MJ_HTTPGETDATA%d%d"), pSink->m_wServerID, iRand); if (!g_Event) g_Event = CreateEvent(NULL, false, false, csEvent); //人工重置,有信号 m_bRun = true; pCAttemperEngineSink = pSink; m_hThread = (HANDLE)_beginthreadex(NULL, 0, &Runs, NULL, 0, &m_uiThreadID); return true; }; //结束 bool CHttpClient::end() { if (!m_hThread) return false; pCAttemperEngineSink = NULL; m_bRun = false; SetEvent(g_Event); return true; } // 进行Url编码 UTF-8 CString CHttpClient::UrlEncode(CString strUnicode) { LPCWSTR unicode = T2CW(strUnicode); int len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, 0, 0, 0, 0); if (!len) return strUnicode; char *utf8 = new char[len + 1]; ZeroMemory(utf8, len + 1); char *utf8temp = utf8; WideCharToMultiByte(CP_UTF8, 0, unicode, -1, utf8, len + 1, 0, 0); utf8[len] = NULL; CString strTemp, strEncodeData; while (*utf8 != 0) { strTemp.Format(_T("%%%2x"), (BYTE)*utf8); strEncodeData += strTemp; ++utf8; } delete[]utf8temp; return CString(strEncodeData); } //运行 unsigned __stdcall CHttpClient::Runs(void* pParam) { if (g_Event == NULL) { _endthreadex(0); m_hThread = NULL; m_bRun = false; return 0; } CString strResponse; CString Err; if (curl == NULL) { curl = curl_easy_init(); } // 线程开始 while (m_bRun && WAIT_OBJECT_0 == WaitForSingleObject(g_Event, INFINITE)) //指定的对象为有信号状态,这里确实为有信号状态,直接往下执行 { std::unordered_map Ret = GetLog(); std::unordered_map::iterator it = Ret.begin(); //if (pCAttemperEngineSink ) //{ // CString csTest; // csTest.Format(_T("支付线程获得获得信号,信号获得任务数=%d。"), Ret.size()); // TCHAR szBuffer[600]; // ZeroMemory(szBuffer, sizeof(TCHAR) * 600); // StringCchCopy(szBuffer, 600, csTest); // CShowTime aa(szBuffer, true, 99999, 99999); //} CString csRet = _T(""); for (; it != Ret.end();it++) { DWORD dStart = GetTickCount(); //构建请求 CString csGet; GETDUILIEBASE_EX_LIST getData = it->second; for (int i = 0; i < 10; i++) { switch (getData.dDataList[i].CommendID) { case 1://获取手机验证码 { OnGetIphoneNumber(CString(getData.dDataList[i].szIphoneNum), 0, getData.dDataList[i].dwSocketID); break; } default: break; } } if (pCAttemperEngineSink) { dStart = GetTickCount() - dStart; CString csTest; getData.dDataList[0].dwSocketID = 0x00; csTest.Format(_T("处理完成了(%d)的请求,耗时=%d。\r\n处理结果=%s"), getData.dDataList[0].dwSocketID, dStart, csRet); CShowTime aa(csTest, true, 99999, 99999); } } Ret.clear(); //if (pCAttemperEngineSink ) //{ // CString csTest; // csTest.Format(_T("处理完成,进入休眠。")); // CShowTime aa(csTest, true, 99999, 99999); //} } //if (pCAttemperEngineSink ) //{ // CString csTest; // csTest.Format(_T("支付线程退出。")); // CShowTime aa(csTest, true, 99999, 99999); //} m_bRun = false; if (g_Event) { CloseHandle(g_Event); g_Event = NULL; } GetLog(); if (curl != NULL) { curl_easy_cleanup(curl); curl = NULL; } _endthreadex(0); m_hThread = NULL; return 0; } static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *) { if (itype == CURLINFO_TEXT) { //printf("[TEXT]%s\n", pData); } else if (itype == CURLINFO_HEADER_IN) { printf("[HEADER_IN]%s\n", pData); } else if (itype == CURLINFO_HEADER_OUT) { printf("[HEADER_OUT]%s\n", pData); } else if (itype == CURLINFO_DATA_IN) { printf("[DATA_IN]%s\n", pData); } else if (itype == CURLINFO_DATA_OUT) { printf("[DATA_OUT]%s\n", pData); } return 0; } static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid) { std::string* str = dynamic_cast((std::string *)lpVoid); if (NULL == str || NULL == buffer) { return -1; } char* pData = (char*)buffer; str->append(pData, size * nmemb); return nmemb; } int CHttpClient::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse) { CURLcode res; CURL* curl = curl_easy_init(); if (NULL == curl) { return CURLE_FAILED_INIT; } if (m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str()); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3); res = curl_easy_perform(curl); curl_easy_cleanup(curl); return res; } int CHttpClient::Get(const std::string & strUrl, std::string & strResponse) { CURLcode res; if (NULL == curl) { return CURLE_FAILED_INIT; } if (m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Content-Type:application/x-www-form-urlencoded;charset=UTF-8"); headers = curl_slist_append(headers, "Accept:*/*"); headers = curl_slist_append(headers, "User-Agent:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; CIBA)"); headers = curl_slist_append(headers, "Connection:Keep-Alive"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); /** * 当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。 * 如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。 */ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5); res = curl_easy_perform(curl); curl_slist_free_all(headers);//记得要释放 return res; } int CHttpClient::Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath) { CURLcode res; CURL* curl = curl_easy_init(); if (NULL == curl) { return CURLE_FAILED_INIT; } if (m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str()); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); if (NULL == pCaPath) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); } else { //缺省情况就是PEM,所以无需设置,另外支持DER //curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM"); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true); curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath); } curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3); res = curl_easy_perform(curl); curl_easy_cleanup(curl); return res; } int CHttpClient::Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath) { CURLcode res; CURL* curl = curl_easy_init(); if (NULL == curl) { return CURLE_FAILED_INIT; } if (m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); if (NULL == pCaPath) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); } else { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true); curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath); } curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3); res = curl_easy_perform(curl); curl_easy_cleanup(curl); return res; } void CHttpClient::SetDebug(bool bDebug) { m_bDebug = bDebug; } /////////////////////////////////////////////////////////////////////////////////////////////// //获取验证码 bool CHttpClient::OnGetIphoneNumber(CString csIphoneNum, DWORD dwUserID, DWORD dwSocketID) { CString csGet, Err; CString HttpPath = _T(""); if (CServiceUnits::g_pServiceUnits) HttpPath = CServiceUnits::g_pServiceUnits->m_InitParameter.m_HttpPath; HttpPath = _T("http://sms.yht521.com/"); csGet.Format(_T("%s/Sms/AliyunSendSms"), HttpPath); //csGet.Format(_T("http://192.168.0.223:8088/Sms/AliyunSendSms")); std::string szUrl; szUrl = CW2AEX<1024>(csGet).m_psz; std::string csRet; CString csPost; std::string szPost; char TimeScore[15] = { 0 }; time_t t; tm* local; //本地时间 t = time(NULL); local = localtime(&t); //转为本地时间 strftime(TimeScore, 64, "%Y%m%d%H%M%S", local); TimeScore[14] = '\0'; std::string strTime = TimeScore; CString csTime(strTime.c_str()); CString Key = _T(""); CString csMd5; csMd5.Format(_T("%d%s%sf*4$oEmmHA@fuHVD"), 305, csIphoneNum, csTime); TCHAR strMd5[LEN_MD5]; CWHEncrypt md5; md5.MD5Encrypt(csMd5, strMd5); csPost.Format(_T("GameId=%d&Mobile=%s&Time=%s&Sign=%s"),305, csIphoneNum, csTime, strMd5); szPost = CW2AEX<1024>(csPost).m_psz; CHttpClient aa; int iRet = aa.Post(szUrl, szPost, csRet); //post请求 if (pCAttemperEngineSink) { CString bb = CChineseCode::Utf8ToUnicode(csRet.c_str()); CString strTip; strTip.Format(L"验证码请求:%s,Post:%s,收到结果:%d,%s", csGet, csPost, iRet, bb);//新用户ID:%d,dwUserID, CTraceService::TraceString(strTip, TraceLevel_Normal); } if (iRet != SUCCESS) { //处理已经创建的手机绑定 清除状态 if (pCAttemperEngineSink)pCAttemperEngineSink->OnTCPNetworkMainHandleMBLogon(csIphoneNum, dwSocketID); } //解析返回的数据 Json::Reader m_reader; Json::Value m_root; if (!m_reader.parse(csRet, m_root)) return true; int nCode = (INT)m_root["Code"].asInt(); std:string strMsg = m_root["Msg"].asString(); CString strError = CChineseCode::Utf8ToUnicode(strMsg.c_str()); CString strTip; strTip.Format(L"验证码请求1111:%d,Post:%s", nCode, strError);//新用户ID:%d,dwUserID, CTraceService::TraceString(strTip, TraceLevel_Normal); if (nCode != 0) { CString strTip; strTip.Format(L"获取验证码失败原因:%s", strError); CTraceService::TraceString(strTip, TraceLevel_Warning); //处理已经创建的手机绑定 清除状态 if (pCAttemperEngineSink)pCAttemperEngineSink->OnTCPNetworkMainHandleMBLogon(csIphoneNum, dwSocketID); return true; } CString VerfCode = CChineseCode::Utf8ToUnicode((m_root["Body"].asString()).c_str()); if (pCAttemperEngineSink)pCAttemperEngineSink->OnTCPNetworkMainMBLogonMiMa(csIphoneNum, VerfCode, dwSocketID); return true; }