libcurl Multi异步接口使用

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的性能

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章