libcurl库的异步用法
生活随笔
收集整理的這篇文章主要介紹了
libcurl库的异步用法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?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對象。
#include <string> #include <iostream>#include <curl/curl.h> #include <sys/time.h> #include <unistd.h>using namespace std;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_WRITEDATA, &sRsp);return curl; }/*** 使用select函數監聽multi curl文件描述符的狀態* 監聽成功返回0,監聽失敗返回-1*/ int curl_multi_select(CURLM * curl_m) {int ret = 0;struct timeval timeout_tv;fd_set fd_read;fd_set fd_write;fd_set fd_except;int max_fd = -1;// 注意這里一定要清空fdset,curl_multi_fdset不會執行fdset的清空操作 // FD_ZERO(&fd_read);FD_ZERO(&fd_write);FD_ZERO(&fd_except);// 設置select超時時間 // timeout_tv.tv_sec = 1;timeout_tv.tv_usec = 0;// 獲取multi curl需要監聽的文件描述符集合 fd_set // curl_multi_fdset(curl_m, &fd_read, &fd_write, &fd_except, &max_fd);/*** When max_fd returns with -1,* you need to wait a while and then proceed and call curl_multi_perform anyway.* How long to wait? I would suggest 100 milliseconds at least,* but you may want to test it out in your own particular conditions to find a suitable value.*/if (-1 == max_fd){return -1;}/*** 執行監聽,當文件描述符狀態發生改變的時候返回* 返回0,程序調用curl_multi_perform通知curl執行相應操作* 返回-1,表示select錯誤* 注意:即使select超時也需要返回0,具體可以去官網看文檔說明*/int ret_code = ::select(max_fd + 1, &fd_read, &fd_write, &fd_except, &timeout_tv);switch(ret_code){case -1:/* select error */ret = -1;break;case 0:/* select timeout */default:/* one or more of curl's file descriptors say there's data to read or write*/ret = 0;break;}return ret; }#define MULTI_CURL_NUM 3// 這里設置你需要訪問的url // std::string URL = "http://website.com"; // 這里設置代理ip和端口 // std::string PROXY = "ip:port"; // 這里設置超時時間 // unsigned int TIMEOUT = 2000; /* ms *//*** multi curl使用demo*/ int curl_multi_demo(int num) {// 初始化一個multi curl 對象 // CURLM * curl_m = curl_multi_init();std::string RspArray[num];CURL * CurlArray[num];// 設置easy curl對象并添加到multi curl對象中 // for (int idx = 0; idx < num; ++idx){CurlArray[idx] = NULL;CurlArray[idx] = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);if (CurlArray[idx] == NULL){return -1;}curl_multi_add_handle(curl_m, CurlArray[idx]);}/** 調用curl_multi_perform函數執行curl請求* url_multi_perform返回CURLM_CALL_MULTI_PERFORM時,表示需要繼續調用該函數直到返回值不是CURLM_CALL_MULTI_PERFORM為止* running_handles變量返回正在處理的easy curl數量,running_handles為0表示當前沒有正在執行的curl請求*/int running_handles;while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles)){cout << running_handles << endl;}/*** 為了避免循環調用curl_multi_perform產生的cpu持續占用的問題,采用select來監聽文件描述符*/while (running_handles){if (-1 == curl_multi_select(curl_m)){cerr << "select error" << endl;break;} else {// select監聽到事件,調用curl_multi_perform通知curl執行相應的操作 // while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles)){cout << "select: " << running_handles << endl;}}cout << "select: " << running_handles << endl;}// 輸出執行結果 // int msgs_left;CURLMsg * msg;while((msg = curl_multi_info_read(curl_m, &msgs_left))){if (CURLMSG_DONE == msg->msg){int idx;for (idx = 0; idx < num; ++idx){if (msg->easy_handle == CurlArray[idx]) break;}if (idx == num){cerr << "curl not found" << endl;} else{cout << "curl [" << idx << "] completed with status: "<< msg->data.result << endl;cout << "rsp: " << RspArray[idx] << endl;}}}// 這里要注意cleanup的順序 // for (int idx = 0; idx < num; ++idx){curl_multi_remove_handle(curl_m, CurlArray[idx]);}for (int idx = 0; idx < num; ++idx){curl_easy_cleanup(CurlArray[idx]);}curl_multi_cleanup(curl_m);return 0; }/*** easy curl使用demo*/ int curl_easy_demo(int num) {std::string RspArray[num];for (int idx = 0; idx < num; ++idx){CURL * curl = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);CURLcode code = curl_easy_perform(curl);cout << "curl [" << idx << "] completed with status: "<< code << endl;cout << "rsp: " << RspArray[idx] << endl;// clear handle // curl_easy_cleanup(curl);}return 0; }#define USE_MULTI_CURLstruct timeval begin_tv, end_tv;int main(int argc, char * argv[]) {if (argc < 2){return -1;}int num = atoi(argv[1]);// 獲取開始時間 // gettimeofday(&begin_tv, NULL); #ifdef USE_MULTI_CURL// 使用multi接口進行訪問 // curl_multi_demo(num); #else// 使用easy接口進行訪問 // curl_easy_demo(num); #endif// 獲取結束時間 // struct timeval end_tv;gettimeofday(&end_tv, NULL);// 計算執行延時并輸出,用于比較 // int eclapsed = (end_tv.tv_sec - begin_tv.tv_sec) * 1000 +(end_tv.tv_usec - begin_tv.tv_usec) / 1000;cout << "eclapsed time:" << eclapsed << "ms" << endl;return 0; }總結
以上是生活随笔為你收集整理的libcurl库的异步用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用NSURLCache 数据缓存
- 下一篇: 3-7:类与对象下篇——static成员