zoukankan      html  css  js  c++  java
  • CURL 实战下载

    #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%%
    ", 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;
    }
  • 相关阅读:
    SQL Server 复制订阅
    杂谈经验与未来
    泛泰A820L (高通MSM8660 cpu) 3.4内核的CM10.1(Android 4.2.2) 測试版第二版
    hdu1280 前m大的数(数组下标排序)
    Design Pattern Adaptor 适配器设计模式
    ssh命令、ping命令、traceroute 命令所使用的协议
    Android禁止ViewPager的左右滑动
    推荐一款优雅的jquery手风琴特效
    vijos
    iOS 7 UI 过渡指南
  • 原文地址:https://www.cnblogs.com/lizhanzhe/p/10878054.html
Copyright © 2011-2022 走看看