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

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