精华内容
下载资源
问答
  • libcurl进行异步并发

    千次阅读 2018-02-13 10:37:46
    libcurl的easy 接口,easy接口的使用非常的简单,curl_easy_init用来初始化一个easy curl对象,curl_easy_setopt对easy curl对象进行相关设置,最后curl_easy_perform执行curl请求,返回相应结果。easy接口是阻塞的...

            libcurl的easy 接口,easy接口的使用非常的简单,curl_easy_init用来初始化一个easy curl对象,curl_easy_setopt对easy curl对象进行相关设置,最后curl_easy_perform执行curl请求,返回相应结果。easy接口是阻塞的,也就是说必须等到上一个curl请求执行完后,下一个curl请求才能继续执行,在一般的应用场合,这种阻塞的访问方式是没有问题的,但是当程序需要进行多次curl并发请求的时候,easy接口就无能为力了,这个时候curl提供的multi接口就派上用场了.

            相比而言,multi接口的使用会比easy 接口稍微复杂点,毕竟multi接口是依赖easy接口的,首先粗略的讲下其使用流程:curl_multi _init初始化一个multi curl对象,为了同时进行多个curl的并发访问,我们需要初始化多个easy curl对象,使用curl_easy_setopt进行相关设置,然后调用curl_multi _add_handle把easy curl对象添加到multi curl对象中,添加完毕后执行curl_multi_perform方法进行并发的访问,访问结束后curl_multi_remove_handle移除相关easy curl对象,curl_easy_cleanup清除easy curl对象,最后curl_multi_cleanup清除multi curl对象。

        上面的介绍只是给大家一个大概的印象,实际使用中还有很多细节需要注意,好了,代码才能说明一切,下面的例子使用multi curl方式进行多次http并发访问,并输出访问结果。

            

    1. #include <string>  
    2. #include <iostream>  
    3.   
    4. #include <curl/curl.h>  
    5. #include <sys/time.h>  
    6. #include <unistd.h>  
    7.   
    8. using namespace std;  
    9.   
    10. size_t curl_writer(void *buffer, size_t size, size_t count, void * stream)  
    11. {  
    12.     std::string * pStream = static_cast<std::string *>(stream);  
    13.     (*pStream).append((char *)buffer, size * count);  
    14.   
    15.     return size * count;  
    16. };  
    17.   
    18. /** 
    19.  * 生成一个easy curl对象,进行一些简单的设置操作 
    20.  */  
    21. CURL * curl_easy_handler(const std::string & sUrl,  
    22.                          const std::string & sProxy,  
    23.                          std::string & sRsp,  
    24.                          unsigned int uiTimeout)  
    25. {  
    26.     CURL * curl = curl_easy_init();  
    27.   
    28.     curl_easy_setopt(curl, CURLOPT_URL, sUrl.c_str());  
    29.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
    30.   
    31.     if (uiTimeout > 0)  
    32.     {  
    33.         curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, uiTimeout);  
    34.     }  
    35.     if (!sProxy.empty())  
    36.     {  
    37.         curl_easy_setopt(curl, CURLOPT_PROXY, sProxy.c_str());  
    38.     }  
    39.   
    40.     // write function //  
    41.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writer);  
    42.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, &sRsp);  
    43.   
    44.     return curl;  
    45. }  
    46.   
    47. /** 
    48.  * 使用select函数监听multi curl文件描述符的状态 
    49.  * 监听成功返回0,监听失败返回-1 
    50.  */  
    51. int curl_multi_select(CURLM * curl_m)  
    52. {  
    53.     int ret = 0;  
    54.   
    55.     struct timeval timeout_tv;  
    56.     fd_set  fd_read;  
    57.     fd_set  fd_write;  
    58.     fd_set  fd_except;  
    59.     int     max_fd = -1;  
    60.   
    61.     // 注意这里一定要清空fdset,curl_multi_fdset不会执行fdset的清空操作  //  
    62.     FD_ZERO(&fd_read);  
    63.     FD_ZERO(&fd_write);  
    64.     FD_ZERO(&fd_except);  
    65.   
    66.     // 设置select超时时间  //  
    67.     timeout_tv.tv_sec = 1;  
    68.     timeout_tv.tv_usec = 0;  
    69.   
    70.     // 获取multi curl需要监听的文件描述符集合 fd_set //  
    71.     curl_multi_fdset(curl_m, &fd_read, &fd_write, &fd_except, &max_fd);  
    72.   
    73.     /** 
    74.      * When max_fd returns with -1, 
    75.      * you need to wait a while and then proceed and call curl_multi_perform anyway. 
    76.      * How long to wait? I would suggest 100 milliseconds at least, 
    77.      * but you may want to test it out in your own particular conditions to find a suitable value. 
    78.      */  
    79.     if (-1 == max_fd)  
    80.     {  
    81.         return -1;  
    82.     }  
    83.   
    84.     /** 
    85.      * 执行监听,当文件描述符状态发生改变的时候返回 
    86.      * 返回0,程序调用curl_multi_perform通知curl执行相应操作 
    87.      * 返回-1,表示select错误 
    88.      * 注意:即使select超时也需要返回0,具体可以去官网看文档说明 
    89.      */  
    90.     int ret_code = ::select(max_fd + 1, &fd_read, &fd_write, &fd_except, &timeout_tv);  
    91.     switch(ret_code)  
    92.     {  
    93.     case -1:  
    94.         /* select error */  
    95.         ret = -1;  
    96.         break;  
    97.     case 0:  
    98.         /* select timeout */  
    99.     default:  
    100.         /* one or more of curl's file descriptors say there's data to read or write*/  
    101.         ret = 0;  
    102.         break;  
    103.     }  
    104.   
    105.     return ret;  
    106. }  
    107.   
    108. #define MULTI_CURL_NUM 3  
    109.   
    110. // 这里设置你需要访问的url //  
    111. std::string     URL     = "http://website.com";  
    112. // 这里设置代理ip和端口  //  
    113. std::string     PROXY   = "ip:port";  
    114. // 这里设置超时时间  //  
    115. unsigned int    TIMEOUT = 2000; /* ms */  
    116.   
    117. /** 
    118.  * multi curl使用demo 
    119.  */  
    120. int curl_multi_demo(int num)  
    121. {  
    122.     // 初始化一个multi curl 对象 //  
    123.     CURLM * curl_m = curl_multi_init();  
    124.   
    125.     std::string     RspArray[num];  
    126.     CURL *          CurlArray[num];  
    127.   
    128.     // 设置easy curl对象并添加到multi curl对象中  //  
    129.     for (int idx = 0; idx < num; ++idx)  
    130.     {  
    131.         CurlArray[idx] = NULL;  
    132.         CurlArray[idx] = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);  
    133.         if (CurlArray[idx] == NULL)  
    134.         {  
    135.             return -1;  
    136.         }  
    137.         curl_multi_add_handle(curl_m, CurlArray[idx]);  
    138.     }  
    139.   
    140.     /* 
    141.      * 调用curl_multi_perform函数执行curl请求 
    142.      * url_multi_perform返回CURLM_CALL_MULTI_PERFORM时,表示需要继续调用该函数直到返回值不是CURLM_CALL_MULTI_PERFORM为止 
    143.      * running_handles变量返回正在处理的easy curl数量,running_handles为0表示当前没有正在执行的curl请求 
    144.      */  
    145.     int running_handles;  
    146.     while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles))////执行并发请求,非阻塞,立即返回
    147.     {  
    148.         cout << running_handles << endl;  
    149.     }  
    150.   
    151.     /** 
    152.      * 为了避免循环调用curl_multi_perform产生的cpu持续占用的问题,采用select来监听文件描述符 
    153.      */  
    154.     while (running_handles)  
    155.     {  
    156.         if (-1 == curl_multi_select(curl_m))  
    157.         {  
    158.             cerr << "select error" << endl;  
    159.             break;  
    160.         } else {  
    161.             // select监听到事件,调用curl_multi_perform通知curl执行相应的操作 //  
    162.             while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles))  
    163.             {  
    164.                 cout << "select: " << running_handles << endl;  
    165.             }  
    166.         }  
    167.         cout << "select: " << running_handles << endl;  
    168.     }  
    169.   
    170.     // 输出执行结果 //  
    171.     int         msgs_left;  
    172.     CURLMsg *   msg;  
    173.     while((msg = curl_multi_info_read(curl_m, &msgs_left)))  
    174.     {  
    175.         if (CURLMSG_DONE == msg->msg)  
    176.         {  
    177.             int idx;  
    178.             for (idx = 0; idx < num; ++idx)  
    179.             {  
    180.                 if (msg->easy_handle == CurlArray[idx]) break;  
    181.             }  
    182.   
    183.             if (idx == num)  
    184.             {  
    185.                 cerr << "curl not found" << endl;  
    186.             } else  
    187.             {  
    188.                 cout << "curl [" << idx << "] completed with status: "  
    189.                         << msg->data.result << endl;  
    190.                 cout << "rsp: " << RspArray[idx] << endl;  
    191.             }  
    192.         }  
    193.     }  
    194.   
    195.     // 这里要注意cleanup的顺序 //  
    196.     for (int idx = 0; idx < num; ++idx)  
    197.     {  
    198.         curl_multi_remove_handle(curl_m, CurlArray[idx]);  
    199.     }  
    200.   
    201.     for (int idx = 0; idx < num; ++idx)  
    202.     {  
    203.         curl_easy_cleanup(CurlArray[idx]);  
    204.     }  
    205.   
    206.     curl_multi_cleanup(curl_m);  
    207.   
    208.     return 0;  
    209. }  
    210.   
    211. /** 
    212.  * easy curl使用demo 
    213.  */  
    214. int curl_easy_demo(int num)  
    215. {  
    216.     std::string     RspArray[num];  
    217.   
    218.     for (int idx = 0; idx < num; ++idx)  
    219.     {  
    220.         CURL * curl = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);  
    221.         CURLcode code = curl_easy_perform(curl);  
    222.         cout << "curl [" << idx << "] completed with status: "  
    223.                 << code << endl;  
    224.         cout << "rsp: " << RspArray[idx] << endl;  
    225.   
    226.         // clear handle //  
    227.         curl_easy_cleanup(curl);  
    228.     }  
    229.   
    230.     return 0;  
    231. }  
    232.   
    233. #define USE_MULTI_CURL  
    234.   
    235. struct timeval begin_tv, end_tv;  
    236.   
    237. int main(int argc, char * argv[])  
    238. {  
    239.     if (argc < 2)  
    240.     {  
    241.         return -1;  
    242.     }  
    243.     int num = atoi(argv[1]);  
    244.   
    245.     // 获取开始时间 //  
    246.     gettimeofday(&begin_tv, NULL);  
    247. #ifdef USE_MULTI_CURL  
    248.     // 使用multi接口进行访问 //  
    249.     curl_multi_demo(num);  
    250. #else  
    251.     // 使用easy接口进行访问 //  
    252.     curl_easy_demo(num);  
    253. #endif  
    254.     // 获取结束时间  //  
    255.     struct timeval end_tv;  
    256.     gettimeofday(&end_tv, NULL);  
    257.   
    258.     // 计算执行延时并输出,用于比较  //  
    259.     int eclapsed = (end_tv.tv_sec - begin_tv.tv_sec) * 1000 +  
    260.                    (end_tv.tv_usec - begin_tv.tv_usec) / 1000;  
    261.   
    262.     cout << "eclapsed time:" << eclapsed << "ms" << endl;  
    263.   
    264.     return 0;  
    265. }  

    curl官网上提供的文件上传例子:

    1. /* This is an example application source code using the multi interface 
    2.  * to do a multipart formpost without "blocking". */  
    3. #include <stdio.h>  
    4. #include <string.h>  
    5. #include <sys/time.h>  
    6.   
    7. #include <curl/curl.h>  
    8.   
    9. int main(void)  
    10. {  
    11.   CURL *curl;  
    12.   
    13.   CURLM *multi_handle;  
    14.   int still_running;  
    15.   
    16.   struct curl_httppost *formpost=NULL;  
    17.   struct curl_httppost *lastptr=NULL;  
    18.   struct curl_slist *headerlist=NULL;  
    19.   static const char buf[] = "Expect:";  
    20.   
    21.   /* Fill in the file upload field. This makes libcurl load data from 
    22.      the given file name when curl_easy_perform() is called. */  
    23.   curl_formadd(&formpost,  
    24.                &lastptr,  
    25.                CURLFORM_COPYNAME, "sendfile",  
    26.                CURLFORM_FILE, "postit2.c",  
    27.                CURLFORM_END);  
    28.   
    29.   /* Fill in the filename field */  
    30.   curl_formadd(&formpost,  
    31.                &lastptr,  
    32.                CURLFORM_COPYNAME, "filename",  
    33.                CURLFORM_COPYCONTENTS, "postit2.c",  
    34.                CURLFORM_END);  
    35.   
    36.   /* Fill in the submit field too, even if this is rarely needed */  
    37.   curl_formadd(&formpost,  
    38.                &lastptr,  
    39.                CURLFORM_COPYNAME, "submit",  
    40.                CURLFORM_COPYCONTENTS, "send",  
    41.                CURLFORM_END);  
    42.   
    43.   curl = curl_easy_init();  
    44.   multi_handle = curl_multi_init();  
    45.   
    46.   /* initalize custom header list (stating that Expect: 100-continue is not 
    47.      wanted */  
    48.   headerlist = curl_slist_append(headerlist, buf);  
    49.   if(curl && multi_handle) {  
    50.   
    51.     /* what URL that receives this POST */  
    52.     curl_easy_setopt(curl, CURLOPT_URL, "http://www.example.com/upload.cgi");  
    53.     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);  
    54.   
    55.     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);  
    56.     curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);  
    57.   
    58.     curl_multi_add_handle(multi_handle, curl);  
    59.   
    60.     curl_multi_perform(multi_handle, &still_running);  
    61.   
    62.     do {  
    63.       struct timeval timeout;  
    64.       int rc; /* select() return code */  
    65.   
    66.       fd_set fdread;  
    67.       fd_set fdwrite;  
    68.       fd_set fdexcep;  
    69.       int maxfd = -1;  
    70.   
    71.       long curl_timeo = -1;  
    72.   
    73.       FD_ZERO(&fdread);  
    74.       FD_ZERO(&fdwrite);  
    75.       FD_ZERO(&fdexcep);  
    76.   
    77.       /* set a suitable timeout to play around with */  
    78.       timeout.tv_sec = 1;  
    79.       timeout.tv_usec = 0;  
    80.   
    81.       curl_multi_timeout(multi_handle, &curl_timeo);  
    82.       if(curl_timeo >= 0) {  
    83.         timeout.tv_sec = curl_timeo / 1000;  
    84.         if(timeout.tv_sec > 1)  
    85.           timeout.tv_sec = 1;  
    86.         else  
    87.           timeout.tv_usec = (curl_timeo % 1000) * 1000;  
    88.       }  
    89.   
    90.       /* get file descriptors from the transfers */  
    91.       curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);  
    92.   
    93.       /* In a real-world program you OF COURSE check the return code of the 
    94.          function calls.  On success, the value of maxfd is guaranteed to be 
    95.          greater or equal than -1.  We call select(maxfd + 1, ...), specially in 
    96.          case of (maxfd == -1), we call select(0, ...), which is basically equal 
    97.          to sleep. */  
    98.   
    99.       rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);  
    100.   
    101.       switch(rc) {  
    102.       case -1:  
    103.         /* select error */  
    104.         break;  
    105.       case 0:  
    106.       default:  
    107.         /* timeout or readable/writable sockets */  
    108.         printf("perform!\n");  
    109.         curl_multi_perform(multi_handle, &still_running);  
    110.         printf("running: %d!\n", still_running);  
    111.         break;  
    112.       }  
    113.     } while(still_running);  
    114.   
    115.     curl_multi_cleanup(multi_handle);  
    116.   
    117.     /* always cleanup */  
    118.     curl_easy_cleanup(curl);  
    119.   
    120.     /* then cleanup the formpost chain */  
    121.     curl_formfree(formpost);  
    122.   
    123.     /* free slist */  
    124.     curl_slist_free_all (headerlist);  
    125.   }  
    126.   return 0;  
    127. }  


    展开全文
  • //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);...

    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)\n");
            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\n", 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\n", 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();
    }

    转载于:https://www.cnblogs.com/walkinginthesun/p/9621198.html

    展开全文
  • libcurl Multi异步接口使用

    千次阅读 2020-03-21 09:31:43
    1、multi异步接口实现文件上传demo 《1》、设置easy接口 #include <curl/curl.h> #include <curl/multi.h> /* mutil 句柄的最大连接数 */ #define MAX_CONNECT_HANDLE_NUMS (15) /* 客制化的私有数据...

    1、multi异步接口实现文件上传demo

    《1》、设置easy接口

    #include <curl/curl.h>
    #include <curl/multi.h>
    
    /* mutil 句柄的最大连接数 */
    #define  MAX_CONNECT_HANDLE_NUMS  (15)
    
    /* 客制化的私有数据结构体 */
    typedef struct CustomPrivData
    {
        curl_mime *mime;
        struct curl_slist *headers;
        FILE* wfd;
    }CustomPrivData;
    
       curl_global_init(CURL_GLOBAL_ALL);
        
        CURLM * m_MultiHandle  = curl_multi_init();
        curl_multi_setopt(m_MultiHandle, CURLMOPT_MAXCONNECTS, MAX_CONNECT_HANDLE_NUMS);
    
        CURLSH* m_ShareHandle = curl_share_init();
        if(m_ShareHandle)
        {
            /* 设置DNS共享,不然每个easyhandle执行时都要解析一遍DNS */
            curl_share_setopt(m_ShareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
        }
    
    CURL*   EasyCurlHandle = curl_easy_init();
    
        if(EasyCurlHandle)
        {
            curl_easy_setopt(EasyCurlHandle, CURLOPT_FOLLOWLOCATION, 1L);
    
            struct curl_slist *headers = NULL;
            char Auth_header[256]={0};
            snprintf(Auth_header, 256, "Authorization:Bearer %s","test21334242");
            headers = curl_slist_append(headers, Auth_header);
    
            CustomPrivData* PrivData = new CustomPrivData;
            memset(PrivData, 0, sizeof(CustomPrivData));
    
            //headers = curl_slist_append(headers, "User-agent:Mozilla/5.0(Windows NT 6.1;Win64; x64)");
            //headers = curl_slist_append(headers, "Accept-Encoding:gzip,deflate");
            //headers = curl_slist_append(headers, "Accept-Language:zh-CN,zh;q=0.9");
    
            curl_easy_setopt(EasyCurlHandle, CURLOPT_HTTPHEADER, headers);
            PrivData->headers = headers;
    
            /* 设置DNS cache的超时时间为120s */
            curl_easy_setopt(EasyCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 60*2);
            curl_easy_setopt(EasyCurlHandle, CURLOPT_SHARE, m_ShareHandle);
    
            curl_easy_setopt(EasyCurlHandle, CURLOPT_URL, url);         /* URL地址设置 */
            curl_easy_setopt(EasyCurlHandle, CURLOPT_NOSIGNAL, 1L);
    
            //curl_easy_setopt(m_EasyCurlHandle, CURLOPT_WRITEFUNCTION, NULL);
            //curl_easy_setopt(m_EasyCurlHandle, CURLOPT_WRITEDATA, NULL);
            curl_easy_setopt(EasyCurlHandle, CURLOPT_VERBOSE, 1);
    
            curl_easy_setopt(EasyCurlHandle, CURLOPT_CUSTOMREQUEST, "POST");
            curl_easy_setopt(EasyCurlHandle, CURLOPT_FOLLOWLOCATION, 1L);
            curl_easy_setopt(EasyCurlHandle, CURLOPT_DEFAULT_PROTOCOL, "https");
            
            curl_mime *mime;
            curl_mimepart *part;
            mime = curl_mime_init(EasyCurlHandle);
            part = curl_mime_addpart(mime);
            curl_mime_name(part, "file");
            curl_mime_filedata(part, file_path);
            curl_easy_setopt(EasyCurlHandle, CURLOPT_MIMEPOST, mime);
    
            PrivData->mime = mime;
    		/* 设置私有数据用于curl_multi_perform执行后区分不同easy句柄 */
            curl_easy_setopt(EasyCurlHandle, CURLOPT_PRIVATE, PrivData);
    
           /* 添加到multi句柄 */
            curl_multi_add_handle(m_MultiHandle, EasyCurlHandle);
    
            /* headers、mime不能在此处释放 ,否则调用multi接口时奔溃*/
            //curl_slist_free_all(headers);
            //curl_mime_free(mime);
        }
    
    

    以上有两点注意:
    1)、使用share接口实现DNS共享,加快处理速度;
    2)、使用curl_easy_setopt(EasyCurlHandle, CURLOPT_PRIVATE, PrivData)设置私有数据,用于curl_multi_info_read调用之后区分不同的easyhandle;

    《2》、开启线程处理函数

    void* MultiperformFunc(void* ptr)
    {
        m_IsStillRuning = true;
        int msgs_left = 0;
        int still_running = 0;
    
        while(m_IsStillRuning)
        {
            CURLMcode mcode = curl_multi_perform(m_MultiHandle, &still_running);
            while(mcode == CURLM_CALL_MULTI_PERFORM)
            {
                cout << "................ CURLM_CALL_MULTI_PERFORM ..............";
                mcode = curl_multi_perform(m_MultiHandle, &still_running);
            }
            //LOG_DEBUG << "still_running: " << still_running;
    
            CURLMsg *msg = NULL;
            int numfds = 0;
            /* wait for activity, timeout or "nothing" */
            int res = curl_multi_wait(m_MultiHandle, NULL, 0, 1000, &numfds);
            
            while((msg = curl_multi_info_read(m_MultiHandle, &msgs_left)))
            {
                if(msg->msg == CURLMSG_DONE)
                {
                    CustomPrivData* PrivData = NULL;
                    CURL *e = msg->easy_handle;
                    curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &PrivData);
                    //fprintf(stderr, "R: %d - %s <%s>\n",msg->data.result, curl_easy_strerror(msg->data.result), wfd);
                    if(PrivData)
                    {
                    	/* 处理每个easyhandle的私有数据 */
                        if(PrivData->wfd)
                            fclose(PrivData->wfd);
                        if(PrivData->headers)
                            curl_slist_free_all(PrivData->headers);
                        if(PrivData->mime)
                            curl_mime_free(PrivData->mime);
    
                        delete PrivData;
                        PrivData = NULL;
                    }
                    
                    /*当一个easy handler传输完成,此easy handler仍然仍然停留在multi stack中,
                    调用curl_multi_remove_handle将其从multi stack中移除,然后调用curl_easy_cleanup将其关闭*/
                    curl_multi_remove_handle(m_MultiHandle, e);
                    curl_easy_cleanup(e);
                }
                else
                {
                    //fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg);
                    cout << "curl Error: " << msg->msg;
                }
            }
    
            usleep(30*1000);
        }
    }
    

    2、参考

    《1》、libcurl采用curl_multi_perform() + curl_multi_wait()方式实现异步高性能l发送数据的方法
    《2》、libcurl的share interface与curl_easy_perform的性能

    展开全文
  • 最近在工作中用到了libcurl请求大量网页,感觉使用多线程的方式线程数太高的话会影响性能,然后就写了一个简单的基于libcurl和reactor模型的框架,实现单线程高并发,不需要考虑竞争条件的问题,提高性能的同时也能...
  • 最近在工作中用到了libcurl请求大量网页,感觉使用多线程的方式线程数太高的话会影响性能,然后就写了一个简单的基于libcurl和reactor模型的框架,实现单线程高并发,不需要考虑竞争条件的问题,提高性能的同时也能...
  • 使用libcurl支持的Future的异步HTTP客户端的实现。 用法 首先,将其添加到您的Cargo.toml : [ dependencies ] tokio-curl = " 0.1 " 接下来,将其添加到您的板条箱中: extern crate tokio_curl; 执照 该项目...
  • 最近在工作中用到了libcurl请求大量网页,感觉使用多线程的方式线程数太高的话会影响性能,然后就写了一个简单的基于libcurl和reactor模型的框架,实现单线程高并发,不需要考虑竞争条件的问题,提高性能的同时也能...
  •  curl是一款利用URL语法进行文件传输的工具,它支持多种协议,包括FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET等,我们既可以在命令行上使用它,也可以利用 ...相信大部分同学都应该使用过libcurl的easy 接口,ea

    转载自:http://blog.csdn.net/zxgfa/article/details/8302059

     curl是一款利用URL语法进行文件传输的工具,它支持多种协议,包括FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET等,我们既可以在命令行上使用它,也可以利用 libcurl进行相关编程。相信大部分同学都应该使用过libcurl的easy 接口,easy接口的使用非常的简单,curl_easy_init用来初始化一个easy curl对象,curl_easy_setopt对easy curl对象进行相关设置,最后curl_easy_perform执行curl请求,返回相应结果。easy接口是阻塞的,也就是说必须等到上一个curl请求执行完后,下一个curl请求才能继续执行,在一般的应用场合,这种阻塞的访问方式是没有问题的,但是当程序需要进行多次curl并发请求的时候,easy接口就无能为力了,这个时候curl提供的multi接口就派上用场了,网上关于libcurl的multi接口的使用资料比较少(百度出来的大部分都是php multi curl的资料),curl官网上貌似也只有相关函数的说明,有实际demo才能让我们更快速的上手使用,所以下面结合实际例子来讲讲multi curl接口的使用方法。

        相比而言,multi接口的使用会比easy 接口稍微复杂点,毕竟multi接口是依赖easy接口的,首先粗略的讲下其使用流程:curl_multi _init初始化一个multi curl对象,为了同时进行多个curl的并发访问,我们需要初始化多个easy curl对象,使用curl_easy_setopt进行相关设置,然后调用curl_multi _add_handle把easy curl对象添加到multi curl对象中,添加完毕后执行curl_multi_perform方法进行并发的访问,访问结束后curl_multi_remove_handle移除相关easy curl对象,curl_easy_cleanup清除easy curl对象,最后curl_multi_cleanup清除multi curl对象。

        上面的介绍只是给大家一个大概的印象,实际使用中还有很多细节需要注意,好了,代码才能说明一切,下面的例子使用multi curl方式进行多次http并发访问,并输出访问结果。

    1. #include <string>  
    2. #include <iostream>  
    3.   
    4. #include <curl/curl.h>  
    5. #include <sys/time.h>  
    6. #include <unistd.h>  
    7.   
    8. using namespace std;  
    9.   
    10. size_t curl_writer(void *buffer, size_t size, size_t count, void * stream)  
    11. {  
    12.     std::string * pStream = static_cast<std::string *>(stream);  
    13.     (*pStream).append((char *)buffer, size * count);  
    14.   
    15.     return size * count;  
    16. };  
    17.   
    18. /** 
    19.  * 生成一个easy curl对象,进行一些简单的设置操作 
    20.  */  
    21. CURL * curl_easy_handler(const std::string & sUrl,  
    22.                          const std::string & sProxy,  
    23.                          std::string & sRsp,  
    24.                          unsigned int uiTimeout)  
    25. {  
    26.     CURL * curl = curl_easy_init();  
    27.   
    28.     curl_easy_setopt(curl, CURLOPT_URL, sUrl.c_str());  
    29.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
    30.   
    31.     if (uiTimeout > 0)  
    32.     {  
    33.         curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, uiTimeout);  
    34.     }  
    35.     if (!sProxy.empty())  
    36.     {  
    37.         curl_easy_setopt(curl, CURLOPT_PROXY, sProxy.c_str());  
    38.     }  
    39.   
    40.     // write function //  
    41.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writer);  
    42.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, &sRsp);  
    43.   
    44.     return curl;  
    45. }  
    46.   
    47. /** 
    48.  * 使用select函数监听multi curl文件描述符的状态 
    49.  * 监听成功返回0,监听失败返回-1 
    50.  */  
    51. int curl_multi_select(CURLM * curl_m)  
    52. {  
    53.     int ret = 0;  
    54.   
    55.     struct timeval timeout_tv;  
    56.     fd_set  fd_read;  
    57.     fd_set  fd_write;  
    58.     fd_set  fd_except;  
    59.     int     max_fd = -1;  
    60.   
    61.     // 注意这里一定要清空fdset,curl_multi_fdset不会执行fdset的清空操作  //  
    62.     FD_ZERO(&fd_read);  
    63.     FD_ZERO(&fd_write);  
    64.     FD_ZERO(&fd_except);  
    65.   
    66.     // 设置select超时时间  //  
    67.     timeout_tv.tv_sec = 1;  
    68.     timeout_tv.tv_usec = 0;  
    69.   
    70.     // 获取multi curl需要监听的文件描述符集合 fd_set //  
    71.     curl_multi_fdset(curl_m, &fd_read, &fd_write, &fd_except, &max_fd);  
    72.   
    73.     /** 
    74.      * When max_fd returns with -1, 
    75.      * you need to wait a while and then proceed and call curl_multi_perform anyway. 
    76.      * How long to wait? I would suggest 100 milliseconds at least, 
    77.      * but you may want to test it out in your own particular conditions to find a suitable value. 
    78.      */  
    79.     if (-1 == max_fd)  
    80.     {  
    81.         return -1;  
    82.     }  
    83.   
    84.     /** 
    85.      * 执行监听,当文件描述符状态发生改变的时候返回 
    86.      * 返回0,程序调用curl_multi_perform通知curl执行相应操作 
    87.      * 返回-1,表示select错误 
    88.      * 注意:即使select超时也需要返回0,具体可以去官网看文档说明 
    89.      */  
    90.     int ret_code = ::select(max_fd + 1, &fd_read, &fd_write, &fd_except, &timeout_tv);  
    91.     switch(ret_code)  
    92.     {  
    93.     case -1:  
    94.         /* select error */  
    95.         ret = -1;  
    96.         break;  
    97.     case 0:  
    98.         /* select timeout */  
    99.     default:  
    100.         /* one or more of curl's file descriptors say there's data to read or write*/  
    101.         ret = 0;  
    102.         break;  
    103.     }  
    104.   
    105.     return ret;  
    106. }  
    107.   
    108. #define MULTI_CURL_NUM 3  
    109.   
    110. // 这里设置你需要访问的url //  
    111. std::string     URL     = "http://website.com";  
    112. // 这里设置代理ip和端口  //  
    113. std::string     PROXY   = "ip:port";  
    114. // 这里设置超时时间  //  
    115. unsigned int    TIMEOUT = 2000; /* ms */  
    116.   
    117. /** 
    118.  * multi curl使用demo 
    119.  */  
    120. int curl_multi_demo(int num)  
    121. {  
    122.     // 初始化一个multi curl 对象 //  
    123.     CURLM * curl_m = curl_multi_init();  
    124.   
    125.     std::string     RspArray[num];  
    126.     CURL *          CurlArray[num];  
    127.   
    128.     // 设置easy curl对象并添加到multi curl对象中  //  
    129.     for (int idx = 0; idx < num; ++idx)  
    130.     {  
    131.         CurlArray[idx] = NULL;  
    132.         CurlArray[idx] = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);  
    133.         if (CurlArray[idx] == NULL)  
    134.         {  
    135.             return -1;  
    136.         }  
    137.         curl_multi_add_handle(curl_m, CurlArray[idx]);  
    138.     }  
    139.   
    140.     /* 
    141.      * 调用curl_multi_perform函数执行curl请求 
    142.      * url_multi_perform返回CURLM_CALL_MULTI_PERFORM时,表示需要继续调用该函数直到返回值不是CURLM_CALL_MULTI_PERFORM为止 
    143.      * running_handles变量返回正在处理的easy curl数量,running_handles为0表示当前没有正在执行的curl请求 
    144.      */  
    145.     int running_handles;  
    146.     while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles))  
    147.     {  
    148.         cout << running_handles << endl;  
    149.     }  
    150.   
    151.     /** 
    152.      * 为了避免循环调用curl_multi_perform产生的cpu持续占用的问题,采用select来监听文件描述符 
    153.      */  
    154.     while (running_handles)  
    155.     {  
    156.         if (-1 == curl_multi_select(curl_m))  
    157.         {  
    158.             cerr << "select error" << endl;  
    159.             break;  
    160.         } else {  
    161.             // select监听到事件,调用curl_multi_perform通知curl执行相应的操作 //  
    162.             while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles))  
    163.             {  
    164.                 cout << "select: " << running_handles << endl;  
    165.             }  
    166.         }  
    167.         cout << "select: " << running_handles << endl;  
    168.     }  
    169.   
    170.     // 输出执行结果 //  
    171.     int         msgs_left;  
    172.     CURLMsg *   msg;  
    173.     while((msg = curl_multi_info_read(curl_m, &msgs_left)))  
    174.     {  
    175.         if (CURLMSG_DONE == msg->msg)  
    176.         {  
    177.             int idx;  
    178.             for (idx = 0; idx < num; ++idx)  
    179.             {  
    180.                 if (msg->easy_handle == CurlArray[idx]) break;  
    181.             }  
    182.   
    183.             if (idx == num)  
    184.             {  
    185.                 cerr << "curl not found" << endl;  
    186.             } else  
    187.             {  
    188.                 cout << "curl [" << idx << "] completed with status: "  
    189.                         << msg->data.result << endl;  
    190.                 cout << "rsp: " << RspArray[idx] << endl;  
    191.             }  
    192.         }  
    193.     }  
    194.   
    195.     // 这里要注意cleanup的顺序 //  
    196.     for (int idx = 0; idx < num; ++idx)  
    197.     {  
    198.         curl_multi_remove_handle(curl_m, CurlArray[idx]);  
    199.     }  
    200.   
    201.     for (int idx = 0; idx < num; ++idx)  
    202.     {  
    203.         curl_easy_cleanup(CurlArray[idx]);  
    204.     }  
    205.   
    206.     curl_multi_cleanup(curl_m);  
    207.   
    208.     return 0;  
    209. }  
    210.   
    211. /** 
    212.  * easy curl使用demo 
    213.  */  
    214. int curl_easy_demo(int num)  
    215. {  
    216.     std::string     RspArray[num];  
    217.   
    218.     for (int idx = 0; idx < num; ++idx)  
    219.     {  
    220.         CURL * curl = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);  
    221.         CURLcode code = curl_easy_perform(curl);  
    222.         cout << "curl [" << idx << "] completed with status: "  
    223.                 << code << endl;  
    224.         cout << "rsp: " << RspArray[idx] << endl;  
    225.   
    226.         // clear handle //  
    227.         curl_easy_cleanup(curl);  
    228.     }  
    229.   
    230.     return 0;  
    231. }  
    232.   
    233. #define USE_MULTI_CURL  
    234.   
    235. struct timeval begin_tv, end_tv;  
    236.   
    237. int main(int argc, char * argv[])  
    238. {  
    239.     if (argc < 2)  
    240.     {  
    241.         return -1;  
    242.     }  
    243.     int num = atoi(argv[1]);  
    244.   
    245.     // 获取开始时间 //  
    246.     gettimeofday(&begin_tv, NULL);  
    247. #ifdef USE_MULTI_CURL  
    248.     // 使用multi接口进行访问 //  
    249.     curl_multi_demo(num);  
    250. #else  
    251.     // 使用easy接口进行访问 //  
    252.     curl_easy_demo(num);  
    253. #endif  
    254.     // 获取结束时间  //  
    255.     struct timeval end_tv;  
    256.     gettimeofday(&end_tv, NULL);  
    257.   
    258.     // 计算执行延时并输出,用于比较  //  
    259.     int eclapsed = (end_tv.tv_sec - begin_tv.tv_sec) * 1000 +  
    260.                    (end_tv.tv_usec - begin_tv.tv_usec) / 1000;  
    261.   
    262.     cout << "eclapsed time:" << eclapsed << "ms" << endl;  
    263.   
    264.     return 0;  
    265. }  


        上面的代码在关键位置都做了详细的注释,相信应该不难看懂。


      上篇博文讲到了如何使用multicurl来进行http并发访问,今天继续有关curl的主题,来八一八如何使用curl来上传文件,在介绍具体方法之前了解下目前http文件上传的基本实现。

        rfc1867描述了如何使用http协议来上传客户端文件,目前基本上所有的浏览器和web服务器都支持http文件上传,它的使用也十分的简单,具体的来说就是在页面上创建一个form表单,表单的enctype属性为multipart/form-data,action为接收上传文件的cgi url,请求方式为post,在表单中添加type属性为file的input,file input里面选择需要上传的文件,选择好后点击submit,服务器端收到multipart post请求后,会根据相关协议解析请求,然后保存上传的文件内容,Multipart表单示例:

    [html] view plaincopy
    1. <form enctype="multipart/form-data" action="http://host:port/UploadFile" method=post>  
    2.     Upload :<br>  
    3.     <input name="userfile" type="file"><br>  
    4.     text field :<input type="text" name="text" value="text"><br>  
    5.     <input type="submit" value="提交"><input type=reset>  
    6. </form>  


        好了,现在来讲一讲curl的文件上传,对于curl来讲,其实它要完成的任务就是构建一个multipart/formdata HTTP POST请求。类似于往multipart form表单中添加type为file或者text的input item一样,curl也需要我们构造表单中的input item,curl_formadd函数可以帮助我们完成这个任务,它即可以添加普通的name-value section,也可以添加file upload section,下面举几个具体例子:

    1、添加name/content section

    1. curl_formadd(&post, &last, CURLFORM_COPYNAME, "name",   CURLFORM_COPYCONTENTS, "content", CURLFORM_END);  

    2、添加name/content/contenttype section

    1. curl_formadd(&post, &last, CURLFORM_COPYNAME, "name",   CURLFORM_COPYCONTENTS, "content",   CURLFORM_CONTENTTYPE, "type", CURLFORM_END);  

    3、添加 file/filename section

    1. curl_formadd(&post, &last, CURLFORM_COPYNAME, "pic",   CURLFORM_FILE, "demo.jpg", CURLFORM_FILENAME, "upload.pic", CURLFORM_END);     

    4、添加file/contenttype section

    1. curl_formadd(&post, &last, CURLFORM_COPYNAME, "pic",   CURLFORM_FILE, "demo.jpg", CURLFORM_FILENAME, "upload.pic",  CURLFORM_CONTENTTYPE, "image/jpeg", CURLFORM_END);  


         上面的post 和 last都是指向curl_httppost对象的指针, post指向的就是一个由所有section组成的链表的开端,last是该链表的尾指针。当我们添加完所有的form section之后,使用curl_easy_setopt(curl, CURLOPT_HTTPPOST,post)函数设置curl的http post,最后就是调用curl_easy_perform执行请求。需要注意的是,当使用libcurl的POST方式时,如果POST数据的大小大于1024个字节,libcurl不会直接发送POST请求,而是会分为两步执行请求:
        1、发送一个请求,该请求头部包含一个Expect: 100-continue的字段,用来询问server是否愿意接受数据
        2、当接收到从server返回的100-continue的应答后,它才会真正的发起POST请求,将数据发送给server。
        对于文件上传来说,文件大小往往会超过1024个字节,所以如果你确认你的服务器不会拒绝你的文件上传请求的话,可以禁止curl的Expect请求头,具体方法可以去看看我的另外一篇文章《libcurl的使用问题“Expect100-continue” 》。

        最后附上curl官网上提供的文件上传例子:

    1. /* This is an example application source code using the multi interface 
    2.  * to do a multipart formpost without "blocking". */  
    3. #include <stdio.h>  
    4. #include <string.h>  
    5. #include <sys/time.h>  
    6.   
    7. #include <curl/curl.h>  
    8.   
    9. int main(void)  
    10. {  
    11.   CURL *curl;  
    12.   
    13.   CURLM *multi_handle;  
    14.   int still_running;  
    15.   
    16.   struct curl_httppost *formpost=NULL;  
    17.   struct curl_httppost *lastptr=NULL;  
    18.   struct curl_slist *headerlist=NULL;  
    19.   static const char buf[] = "Expect:";  
    20.   
    21.   /* Fill in the file upload field. This makes libcurl load data from 
    22.      the given file name when curl_easy_perform() is called. */  
    23.   curl_formadd(&formpost,  
    24.                &lastptr,  
    25.                CURLFORM_COPYNAME, "sendfile",  
    26.                CURLFORM_FILE, "postit2.c",  
    27.                CURLFORM_END);  
    28.   
    29.   /* Fill in the filename field */  
    30.   curl_formadd(&formpost,  
    31.                &lastptr,  
    32.                CURLFORM_COPYNAME, "filename",  
    33.                CURLFORM_COPYCONTENTS, "postit2.c",  
    34.                CURLFORM_END);  
    35.   
    36.   /* Fill in the submit field too, even if this is rarely needed */  
    37.   curl_formadd(&formpost,  
    38.                &lastptr,  
    39.                CURLFORM_COPYNAME, "submit",  
    40.                CURLFORM_COPYCONTENTS, "send",  
    41.                CURLFORM_END);  
    42.   
    43.   curl = curl_easy_init();  
    44.   multi_handle = curl_multi_init();  
    45.   
    46.   /* initalize custom header list (stating that Expect: 100-continue is not 
    47.      wanted */  
    48.   headerlist = curl_slist_append(headerlist, buf);  
    49.   if(curl && multi_handle) {  
    50.   
    51.     /* what URL that receives this POST */  
    52.     curl_easy_setopt(curl, CURLOPT_URL, "http://www.example.com/upload.cgi");  
    53.     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);  
    54.   
    55.     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);  
    56.     curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);  
    57.   
    58.     curl_multi_add_handle(multi_handle, curl);  
    59.   
    60.     curl_multi_perform(multi_handle, &still_running);  
    61.   
    62.     do {  
    63.       struct timeval timeout;  
    64.       int rc; /* select() return code */  
    65.   
    66.       fd_set fdread;  
    67.       fd_set fdwrite;  
    68.       fd_set fdexcep;  
    69.       int maxfd = -1;  
    70.   
    71.       long curl_timeo = -1;  
    72.   
    73.       FD_ZERO(&fdread);  
    74.       FD_ZERO(&fdwrite);  
    75.       FD_ZERO(&fdexcep);  
    76.   
    77.       /* set a suitable timeout to play around with */  
    78.       timeout.tv_sec = 1;  
    79.       timeout.tv_usec = 0;  
    80.   
    81.       curl_multi_timeout(multi_handle, &curl_timeo);  
    82.       if(curl_timeo >= 0) {  
    83.         timeout.tv_sec = curl_timeo / 1000;  
    84.         if(timeout.tv_sec > 1)  
    85.           timeout.tv_sec = 1;  
    86.         else  
    87.           timeout.tv_usec = (curl_timeo % 1000) * 1000;  
    88.       }  
    89.   
    90.       /* get file descriptors from the transfers */  
    91.       curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);  
    92.   
    93.       /* In a real-world program you OF COURSE check the return code of the 
    94.          function calls.  On success, the value of maxfd is guaranteed to be 
    95.          greater or equal than -1.  We call select(maxfd + 1, ...), specially in 
    96.          case of (maxfd == -1), we call select(0, ...), which is basically equal 
    97.          to sleep. */  
    98.   
    99.       rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);  
    100.   
    101.       switch(rc) {  
    102.       case -1:  
    103.         /* select error */  
    104.         break;  
    105.       case 0:  
    106.       default:  
    107.         /* timeout or readable/writable sockets */  
    108.         printf("perform!\n");  
    109.         curl_multi_perform(multi_handle, &still_running);  
    110.         printf("running: %d!\n", still_running);  
    111.         break;  
    112.       }  
    113.     } while(still_running);  
    114.   
    115.     curl_multi_cleanup(multi_handle);  
    116.   
    117.     /* always cleanup */  
    118.     curl_easy_cleanup(curl);  
    119.   
    120.     /* then cleanup the formpost chain */  
    121.     curl_formfree(formpost);  
    122.   
    123.     /* free slist */  
    124.     curl_slist_free_all (headerlist);  
    125.   }  
    126.   return 0;  
    127. }  


    展开全文
  • 这个小程序只是简单的使用线程池实现libcurl异步请求功能,很多地方还需要优化,之所有厚颜上传到这里,主要有有三个目的。 一个是回报这些天在CSDN上得到的帮助,希望可以帮助到后来的人; 二是感于libcurl编译...
  • 本文承接自前篇博客将Cocos2d-x的...2)实现Android异步任务 下面直接上代码: 1】jni之first.c:first.h无变化,first.c添加如下代码,切记C变量必须把声明方法函数的开始 /* * Copyright (C) 2009 The Android
  • 用于文件上传下载和发送http get,post命令.libcurl不是一个简单的api,是一组api实现的模块,有自己的使用steps. 默认curl是get url 网页,与callback write function连动,写入文件。 2) 两种方案: curl_multi_socket...
  • Libcurl实现文件下载

    千次阅读 2015-11-04 11:00:48
    ... libcurl主要功能就是用不同的协议连接和沟通不同的服务器~也就是相当封装了的sockPHP 支持libcurl(允许你用不同的协议连接和沟通不同的服务器)。, libcurl当前支持http, https, ftp, gop
  • 最近在使用libcurl异步收发消息时碰到一个问题,实在没头绪,有哪位大大可以帮忙看看,多谢 一、目标:使用multi interface实现消息异步收发,两个线程,一个线程发消息,另一个线程收消息 二、问题: 1、环回收...
  • Libcurl实现断点续传

    2019-09-30 08:29:30
    一、LIbcurl简单介绍 其实关于Liccurl的介绍最好的是看官方文档:http://curl.haxx.se/几乎大部分的信息里面都能够查找到。 在这边简要介绍: 1)跨平台特性,几乎所有平台都可以使用 2)有许多其他语言的...
  • libcurl异步请求+http长连接池

    千次阅读 2019-04-14 16:43:03
    2、libcurl easy同步接口不能满足高并发的要求 为了解决以上两个问题,本人通过http长连接池和libcurl multi相关接口解决了该问题,并取得一些效果,现在写出来跟大家分享一下,也算自己的工作笔记; TBC....
  • curl_multi_perform() + select():可以实现libcurl异步多路发送,相对于easy interface有了较大的性能提升,但是select()性能不够好,还受到file descriptors不能大于1024的限制。  本文来探讨
  • libcurl同时封装了select以及poll这两种I/O机制。代码中使用宏HAVE_POLL_FINE对这两者进行分离。如果定义了这个宏,则使用poll,否则使用select。
  • multi接口的使用会比easy 接口稍微复杂点,毕竟multi接口是依赖easy接口的,首先粗略的讲下其使用流程:curl_multi _init初始化一个multi curl对象,为了同时进行多个curl的并发访问,我们需要初始化多个easy curl...
  • frm:... libcurl资料: 百度百科libcurl.libcurl官方文档. Easy Interface:  Easy Interface是libcurl提供的同步接口, 效率高, 容易使用, 推荐没有特殊需求的客户端应用均使用此
  • libcurl 配合epoll 的异步并行server原理

    千次阅读 2017-02-03 22:19:04
    有意思的是它的并行,其实就是libcurl作为网络库提供http请求,然后用epoll做为事件监听来实现整个异步并行调用的。在此基础上,就是如何利用zend api来对整个逻辑的封装了。我们先抛开zend api,单独看看libcurl ...
  • Libcurl实现文件断点续传

    千次阅读 2013-08-21 15:43:28
    一、LIbcurl简单介绍  其实关于Liccurl的介绍最好的是看官方文档:http://curl.haxx.se/ 几乎大部分的信息里面都能够查找到。  在这边简要介绍:  1)跨平台特性,几乎所有平台都可以使用
  • 采用libuv的epoll方式实现异步高性能libcurl发送数据的方法 讲述了采用libcurl发送数据的基础方法和高性能方法,基础方法较为容易但性能一般,高级方法的性能卓越但比较难理解,这里再给出一个保证性能的同时又...
  • 效率很低,就想到用libevent的方式异步调用,libcurl官方也明确提示不建议用multi的select方式,而是推荐结合libevent、libev等库使用。 看了好久,也不知道该如何结合libevent,实现单线程并发调用httppost。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,181
精华内容 872
关键字:

libcurl实现异步