libcurl異步訪問示例


libcurl異步訪問示例

用同步阻塞的方式跑單線程效率太低,每次開新線程去跑curl太浪費資源,沒有必要。
有沒有辦法用IO復用的方式跑單線程?libcurl自帶的curl_multi_wait(封裝了IO復用)可以完成這個工作。

參考地址:

https://www.cnblogs.com/heluan/p/10177475.html
https://blog.csdn.net/whui19890911/article/details/79320408
https://www.cnblogs.com/bugutian/p/4868167.html
https://www.cnblogs.com/dvss/archive/2013/04/11/3014699.html

代碼示例:

#include <iostream>
#include <thread>
#include <string>
#include <mutex>
#include <list>
#include <map>
#include <curl/multi.h>
#include <curl/curl.h>
#include <curl/easy.h>

using namespace std;

typedef unsigned long long UInt64;

std::mutex msgListMtx;
std::list<int>  msgList;
  
// 這里設置你需要訪問的url //  
std::string     BASE_URL = "http://192.168.1.135:19090/vinput?key=";  
// 這里設置代理ip和端口  //  
std::string     PROXY   = "";
// 這里設置超時時間  //  
unsigned int    TIMEOUT = 2000; /* ms */  
unsigned int    globalCnt = 0;

typedef struct SReqNode{
    std::string url;
    std::string respData;
    unsigned int seq;
    SReqNode()
    {
        seq = 0;
        url = "";
        respData = "";
    }
} SReqNode;

size_t curl_writer(void *buffer, size_t size, size_t count, void * stream)  
{
    std::string * pStream = static_cast<std::string *>(stream);  
    (*pStream).append((char *)buffer, size * count);  
  
    return size * count;  
};  
  
/** 
 * 生成一個easy curl對象,進行一些簡單的設置操作 
 */  
CURL * curl_easy_handler(const std::string & sUrl,  
                         const std::string & sProxy,  
                         std::string & sRsp,  
                         unsigned int uiTimeout)  
{  
    CURL * curl = curl_easy_init();  
  
    curl_easy_setopt(curl, CURLOPT_URL, sUrl.c_str());  
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  
    if (uiTimeout > 0)  
    {  
        curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, uiTimeout);  
    }  
    if (!sProxy.empty())  
    {  
        curl_easy_setopt(curl, CURLOPT_PROXY, sProxy.c_str());  
    }  
  
    // write function //  
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writer);  
    //curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writer);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &sRsp);  
  
    return curl;  
}  
void dealMsg(SReqNode* reqNodePtr,int status)
{
    cout << "curl [" << reqNodePtr->seq << "] status: " 
            << status << ",says: "
            << reqNodePtr->respData << endl; 
}

void dealErr()
{
    cout << "Response Msg is not found." << endl; 
}

int key_send_thread()
{
    // 初始化一個multi curl 對象 //  
    CURLM * curl_m = curl_multi_init();
    std::map<UInt64,SReqNode*>  handle2rsp;

    while (1)  
    {
        std::list<int> tmpKeys;
        msgListMtx.lock();
        tmpKeys.swap(msgList);
        msgListMtx.unlock();
        //cout << "SIZE:" << tmpKeys.size() << endl;
        std::list<int>::iterator iter = tmpKeys.begin();
        for (;iter != tmpKeys.end();iter ++)
        {
            CURL* tmpHandler = NULL;
            std::string tmpUrl = BASE_URL + std::to_string(*iter) + "&";
            SReqNode* tmpReqNode = new SReqNode();
            tmpReqNode->seq = globalCnt++;
            tmpReqNode->url = tmpUrl;
            tmpHandler = curl_easy_handler(tmpUrl, PROXY, tmpReqNode->respData, TIMEOUT); 
            if (tmpHandler == NULL)  
            {
                continue;
            }
            handle2rsp[(UInt64)tmpHandler] = tmpReqNode;
            curl_multi_add_handle(curl_m, tmpHandler);  
        }
        
        /* 
         * 調用curl_multi_perform函數執行curl請求 
         * url_multi_perform返回CURLM_CALL_MULTI_PERFORM時,表示需要繼續調用該函數, 直到返回值不是CURLM_CALL_MULTI_PERFORM為止 
         * running_handles變量返回正在處理的easy curl數量,running_handles為0表示當前沒有正在執行的curl請求 
         */  
        int runningHandles;  
        while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &runningHandles))
        {
            cout << runningHandles << endl;  
        }
        int numfds,msgs_left,res;
        res = curl_multi_wait(curl_m, NULL, 0, 200, &numfds);
        CURLMsg *   msg;  
        while((msg = curl_multi_info_read(curl_m, &msgs_left)))
        {
            cout << "while curl_multi_info_read:"  << endl;
            if (CURLMSG_DONE == msg->msg)  
            {
                int idx;  
                std::map<UInt64, SReqNode*>::iterator iter2 = handle2rsp.find(UInt64(msg->easy_handle));
                if (iter2 != handle2rsp.end())
                {
                    dealMsg(iter2->second, msg->data.result);
                    SReqNode* tmpPrt = iter2->second;
                    handle2rsp.erase(iter2);
                    curl_multi_remove_handle(curl_m, msg->easy_handle);
                    curl_easy_cleanup( msg->easy_handle);
                    delete tmpPrt;
                }else{
                    dealErr();
                } 
            }
        }
    }
    curl_multi_cleanup(curl_m);  
  
    return 0;  
}

int main()
{
    thread senderThread(key_send_thread);
    int input;
    while(1)
    {
        cout << "input:";
        cin >> input;
        if (input == 3306)
        {
            break;
        }
        msgListMtx.lock();
        msgList.push_back(input);
        msgListMtx.unlock();
    }
    
    senderThread.join();
    return 0;
}

/********************
### 編譯
g++ testcurl.cpp -I/usr/local/sdk/include -I/usr/local/sdk/include/curl -lidn -lrt -lcrypto -lssl -lz  -lpthread /usr/local/sdk/lib/libcurl.a -std=c++11 -o testurl

### 運行
[root@lh]# ./testurl 
input:
654
input:while curl_multi_info_read:
curl [0] status: 0,says: Recv:654
6546
input:while curl_multi_info_read:
curl [1] status: 0,says: Recv:6546
46
*********************/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM