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
*********************/
转载请注明来源:https://www.cnblogs.com/bugutian/
原文地址:https://www.cnblogs.com/bugutian/p/15319129.html