#include <string> #include <stdio.h> #include <iostream> #include<fstream> #include "curl.h" #ifdef WIN32 #include <corecrt_io.h> #else #include "unistd.h" #include<unistd.h> #endif #include "curl_http.h" #include "md5.h" #include "OperateFile.h" using namespace std; curl_http::curl_http() : list(NULL) { } curl_http::~curl_http() { if (list) { curl_slist_free_all(list); } } void curl_http::add_header(const std::string & header) { list = curl_slist_append(list, header.c_str()); } static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid) { std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid); if (NULL == str || NULL == buffer) { return -1; } char* pData = (char*)buffer; str->append(pData, size * nmemb); return nmemb; } int curl_http::Post(std::string strUrl, std::string strPost, int& statusCode, std::string& strResponse) { CURLcode res; CURL* curl = curl_easy_init(); if (NULL == curl) { return CURLE_FAILED_INIT; } curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); if (list) { curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); } curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); //验证SSL证书 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); //验证主机名的SSL curl_easy_setopt(curl, CURLOPT_POST, 1); //发送一个HTTP POST要求 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str()); //用这个数据发送一个POST 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_TIMEOUT, 3); //整个请求超时时间 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3); //连接阶段超时时间 curl_easy_setopt(curl, CURLOPT_USERAGENT, "pc_student"); //用户代理:标头 res = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode); curl_easy_cleanup(curl); return res; } static size_t OnWriteFile(void* buffer, size_t size, size_t nmemb, void* lpVoid) { FILE* stream = (FILE*)lpVoid; if (nullptr == stream || nullptr == buffer) { return -1; } size_t nWrite = fwrite(buffer, size, nmemb, stream); return nWrite; } int OnProgress(void *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded) { int tmp = 0; long localLen = *(long*)ptr; if ( totalToDownload > 0 ) { tmp = (int)((nowDownloaded + (double)localLen) / (totalToDownload + (double)localLen) * 100); } printf("下载进度%0d%%\r", tmp); return 0; } size_t ProgressFunc(double* pFileLen, double t,// 下载时总大小 double d, // 已经下载大小 double ultotal, // 上传是总大小 double ulnow) // 已经上传大小 { if(t == 0) return 0; *pFileLen = d; return 0; } curl_http_downloader::curl_http_downloader(const std::string& name) : m_file(nullptr) , m_TargetName(name) , m_progress(nullptr) { } curl_http_downloader::~curl_http_downloader() { } bool curl_http_downloader::DownloadFileContent(const std::string& url, const std::string& Targetfilepath, const std::string& Temfilepath, string SizeRange) { CURLcode res; if(OpenFile(Temfilepath,m_file) || OpenFile(Targetfilepath,m_ExitFile)) return false; CURL* _curl = curl_easy_init(); if (nullptr == _curl) { CloseFile(m_file); CloseFile(m_ExitFile); return false; } curl_easy_setopt(_curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, OnWriteFile); curl_easy_setopt(_curl, CURLOPT_WRITEDATA, m_file); curl_easy_setopt(_curl, CURLOPT_NOPROGRESS, false); curl_easy_setopt(_curl, CURLOPT_PROGRESSFUNCTION, OnProgress); curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_LIMIT, 1L); curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_TIME, 5L); curl_easy_setopt(_curl, CURLOPT_HEADER, 0L); curl_easy_setopt(_curl, CURLOPT_NOBODY, 0L); curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1L); //curl_easy_setopt(_curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)1000); if (SizeRange == "") curl_easy_setopt(_curl, CURLOPT_RESUME_FROM, m_LocalFilelen); else curl_easy_setopt(_curl, CURLOPT_RANGE, SizeRange.c_str()); curl_easy_setopt(_curl, CURLOPT_PROGRESSDATA, &m_LocalFilelen); res = curl_easy_perform(_curl); //完成curl_easy_setopt指定的所有选项,并返回状态 curl_easy_cleanup(_curl); CloseFile(m_file); CloseFile(m_ExitFile); if (CURLE_OK == res) return true; else return false; } int curl_http_downloader::Download(const std::string& url, const std::string& path, progressFunc func,string CurrectMD5) { m_filePath = path; #ifdef WIN32 m_TargetFileNamepath = m_filePath + "temp.downloading"; m_Tempinterfilepath = m_filePath + "temp"; #else m_TargetFileNamepath = m_filePath + "temp.downloading"; m_Tempinterfilepath = m_filePath + "temp"; #endif m_LocalFilelen = GetFileLength(m_TargetFileNamepath); //获取已下载文件大小 bool CricleFlags = true; //CricleFlags为dfalse时,说明下载文件错误,重新下载错误部分 bool Downloadflags = true; //Downloadflags为dfalse时,将进行下载与拼接 string range = ""; do{ bool result = DownloadFileContent(url, m_TargetFileNamepath, m_Tempinterfilepath, range); if (result) { std::string fullName = m_filePath + m_TargetName; if(Downloadflags) MergerFile(m_Tempinterfilepath,m_TargetFileNamepath); else ToRightMergerFile(m_TargetFileNamepath, m_Tempinterfilepath); string m_fileMD5 = MD5::getFileMd5(m_TargetFileNamepath); int bmoved = 0; #ifdef WIN32 if (_access(m_TargetFileNamepath.c_str(), 0) == 0) remove(fullName.c_str()); #else if (access(m_TargetFileNamepath.c_str(), 0) == 0) remove(fullName.c_str()); #endif // WIN 32 if(CurrectMD5 == m_fileMD5){ //MD5校验 bmoved = rename(m_TargetFileNamepath.c_str(), fullName.c_str()); remove(m_Tempinterfilepath.c_str()); CricleFlags = true; } else{ ExchangFileName(m_Tempinterfilepath, m_TargetFileNamepath); remove(m_Tempinterfilepath.c_str()); if((Downloadflags = !Downloadflags)) range = ""; else range = "0-" + to_string(m_LocalFilelen-1) ; CricleFlags = false; } if (bmoved) { //std::cerr << "move file: " << m_fileNameTmp << " to: " << fullName <<" failed! "; return -1; } } else{ if(GetFileLength(m_Tempinterfilepath)){ MergerFile(m_Tempinterfilepath,m_TargetFileNamepath); remove(m_Tempinterfilepath.c_str()); } } }while(!CricleFlags); CloseFile(m_file); CloseFile(m_ExitFile); return 0; } int curl_http_downloader::Pause() { if (nullptr != m_download_info) { m_download_info->status = PAUSED; } return 0; }