• libcurl实现的异步下载图片


    DownloadThread.h

    #ifndef DOWNLOAD_THREAD_H
    #define DOWNLOAD_THREAD_H
    
    #include <functional>
    #include <mutex>
    #include <list>
    #include <thread>
    #include <atomic>
    #include <condition_variable>
    #include <curl/curl.h>
    
    typedef struct _Task_
    {
        int                 nIndex;          // 图片index
        std::string         strUrl;          // url: http or https
        std::string         strDescription;   // 用于标识不同的图片(ID),透传到Callback
        std::string         strData;         // 下载得到的数据
        int                 nErrorCode;      // 错误码
        std::string         strErrorMsg;     // 错误信息
    } Task;
    
    using DownloadThreadCallback = std::function<void(const Task&)>;
    
    class DownloadThread
    {
    public:
        DownloadThread() = default;
        ~DownloadThread()=default;
        int Initialize(const DownloadThreadCallback &cb);
        int AddDownloadTask(const Task &task);
        void Finish();
    
    private:
        int InitializeCURL();
        void FinishCURL();
        void Run();
        void CallBack(const Task &t);
    private:
        int                     m_threadId;
        DownloadThreadCallback  m_callback;
        CURL                   *m_curl_handle;
        std::thread            *m_thread;
        std::atomic<bool>       m_bIsRunning;
        std::list<Task>         m_taskList;
        std::mutex              m_mutexTaskList;
        std::condition_variable m_condition;
    };
    
    #endif // DOWNLOAD_THREAD_H
    

    DownloadThread.cpp

    #include "DownloadThread.h"
    
    #include "string.h"
    #include <iostream>
    #include <string>
    
    static size_t
    WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
    {
        size_t realsize = size * nmemb;
    
        char* memory = (char*)malloc(realsize);
        if (memory == NULL) {
            /* out of memory! */
            printf("not enough memory (realloc returned NULL)
    ");
            return 0;
        }
        memcpy(memory, contents, realsize);
    
        Task *t = (Task*)userp;
        t->strData.append(memory, realsize);
    
        free(memory);
    
        return realsize;
    }
    
    
    int DownloadThread::Initialize(const DownloadThreadCallback &cb)
    {
        m_callback = cb;
        if (InitializeCURL() != 0)
        {
            return -1;
        }
    
        m_bIsRunning = true;
        m_thread = new std::thread(&DownloadThread::Run, this);
    }
    
    void DownloadThread::Finish()
    {
        m_bIsRunning = false;
        if (m_thread->joinable())
        {
            m_thread->join();
        }
    
        FinishCURL();
    }
    
    void DownloadThread::FinishCURL()
    {
        /* cleanup curl stuff */
        curl_easy_cleanup(m_curl_handle);
    
        /* we're done with libcurl, so clean it up */
        curl_global_cleanup();
    }
    
    int DownloadThread::AddDownloadTask(const Task &task)
    {
        std::lock_guard<std::mutex> lk(m_mutexTaskList);
        m_taskList.push_back(task);
        m_condition.notify_one();
        return 0;
    }
    
    void DownloadThread::Run()
    {
        while (m_bIsRunning.load())
        {
            //std::cout << "thread is running" << std::endl;
    
            std::unique_lock<std::mutex>  lk(m_mutexTaskList);
            while (m_taskList.empty())
            {
                m_condition.wait(lk);
            }
    
            // get first element
            Task task;
            {
                //std::lock_guard<std::mutex> lkg(m_mutexTaskList);
                task = m_taskList.front();
                m_taskList.pop_front();
            }
            //std::cout << "get task url: " << task.strUrl << std::endl;
            
            CURLcode res;
            curl_easy_setopt(m_curl_handle, CURLOPT_WRITEDATA, (void *)&task);
            /* specify URL to get */
            curl_easy_setopt(m_curl_handle, CURLOPT_URL, const_cast<char*>(task.strUrl.c_str()));
            //curl_easy_setopt(m_curl_handle, CURLOPT_URL, "http://10.66.91.15:7777/ld/smog/2612_src.jpg");
    
            /* get it! */
            res = curl_easy_perform(m_curl_handle);
            /* check for errors */
            if (res != CURLE_OK) {
                // fprintf(stderr, "curl_easy_perform() failed: %s
    ", curl_easy_strerror(res));
                task.nErrorCode = res;
                task.strErrorMsg = curl_easy_strerror(res);
            }
            else {
                /*
                * Now, our chunk.memory points to a memory block that is chunk.size
                * bytes big and contains the remote file.
                *
                * Do something nice with it!
                */
                /*printf("%lu bytes retrieved
    ", task.strData.size());*/
                long lStateCode = 0;
                res = curl_easy_getinfo(m_curl_handle, CURLINFO_RESPONSE_CODE, &lStateCode);
                if (res != CURLE_OK || lStateCode != 200)
                {
                    task.nErrorCode = lStateCode;
                    // task.strErrorMsg = curl_easy_strerror(res);
                    task.strErrorMsg = "http state code is " + std::to_string(lStateCode);
                }
            }
    
            // callback
            CallBack(task);
        }
    }
    
    int DownloadThread::InitializeCURL()
    {
        CURLcode error;
    
        curl_global_init(CURL_GLOBAL_ALL);
        /* init the curl session */
        m_curl_handle = curl_easy_init();
    
        ///* specify URL to get */
        ////curl_easy_setopt(curl_handle, CURLOPT_URL, "http://10.66.91.15:7777/ld/smog/2612_src.jpg");
    
        /* send all data to this function */
        curl_easy_setopt(m_curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
        /* we pass our 'chunk' struct to the callback function */
        /*curl_easy_setopt(m_curl_handle, CURLOPT_WRITEDATA, (void *)this);*/
    
        curl_easy_setopt(m_curl_handle, CURLOPT_FOLLOWLOCATION, 1);
    
    
        /* some servers don't like requests that are made without a user-agent
        field, so we provide one */
        //curl_easy_setopt(m_curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
    
        // https, skip the verification of the server's certificate.
        curl_easy_setopt(m_curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(m_curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
    
        /* 设置连接超时,单位:毫秒 */
        curl_easy_setopt(m_curl_handle, CURLOPT_CONNECTTIMEOUT_MS, 1000L);
    
        // add by yexiaoyogn 10 second time out 
        curl_easy_setopt(m_curl_handle, CURLOPT_TIMEOUT_MS, 2000);
    
        //add yexiaoyong set time out
        curl_easy_setopt(m_curl_handle, CURLOPT_NOSIGNAL, 3);
    }
    
    void DownloadThread::CallBack(const Task &t)
    {
        m_callback(t);
    }
    
    

    demo.cpp

    #include "DownloadThread.h"
    
    #include <iostream>
    #include <thread>
    #include <sstream>
    #include <fstream>
    #include <string>
    
    void TaskCallBack(const Task &t)
    {
        std::ostringstream str;
        str << "callback ...." << std::endl;
        str << "task id is " << t.nIndex << " url is " << t.strUrl << " data size is " << t.strData.size() << std::endl;
        str << "error number is " << t.nErrorCode << " error msg is " << t.strErrorMsg << std::endl;
        std::cout << str.str() << std::endl;
    
        if (t.nErrorCode == 0)
        {
            std::string filename = t.strDescription + ".jpg";
            std::fstream file;
            file.open(filename, std::fstream::in | std::fstream::out | std::fstream::binary | std::fstream::app);
            file.write(t.strData.c_str(), t.strData.size());
            file.close();
        }
    }
    
    
    int main()
    {
        DownloadThread dt;
        dt.Initialize(TaskCallBack);
    
        Task t;
        int cnt = 0;
        while (true)
        {
            t.nIndex = cnt++;
            t.strDescription = "task_"+std::to_string(cnt);
            t.strUrl = "http://10.66.91.15:7777/ld/smog/2612_src.jpg";
            dt.AddDownloadTask(t);
    
            t.nIndex = cnt++;
            t.strDescription = "task_" + std::to_string(cnt);
            t.strUrl = "http://www.baidu.com";
            dt.AddDownloadTask(t);
    
            t.nIndex = cnt++;
            t.strDescription = "task_" + std::to_string(cnt);
            t.strUrl = "http://10.66.91.15:7777/ld/smog/2612_srcxzz.jpg";
            dt.AddDownloadTask(t);
        }
    
        while (true){
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
        dt.Finish();
    }
    
  • 相关阅读:
    转:【More Effective C#】Lambda表达式优化
    转:Highcharts图表控件的使用
    C# subString的理解
    转:TimeSpan的用法
    Android学习笔记一:Android基本组件和Activity生命周期
    IIS 反向代理设置
    WebApi 身份认证解决方案:Basic基础认证
    Calling async method synchronously
    C# 公共类
    aspnet-api-versioning
  • 原文地址:https://www.cnblogs.com/walkinginthesun/p/9621198.html
Copyright © 2020-2023  润新知