c語言libcurl庫的異步用法multi接口的使用會比easy 接口稍微復雜點,畢竟multi接口是依賴easy接口的,,首先粗略的講下其使用流程:curl_multi _init初始化一個multi curl對象,,為了同時進行多個curl的并發(fā)訪問,我們需要初始化多個easy curl對象,,使用curl_easy_setopt進行相關(guān)設(shè)置,,然后調(diào)用curl_multi _add_handle把easy curl對象添加到multi curl對象中,添加完畢后執(zhí)行curl_multi_perform方法進行并發(fā)的訪問,,訪問結(jié)束后curl_multi_remove_handle移除相關(guān)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對象,,進行一些簡單的設(shè)置操作 */ 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函數(shù)監(jiān)聽multi curl文件描述符的狀態(tài) * 監(jiān)聽成功返回0,監(jiān)聽失敗返回-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不會執(zhí)行fdset的清空操作 // FD_ZERO(&fd_read); FD_ZERO(&fd_write); FD_ZERO(&fd_except); // 設(shè)置select超時時間 // timeout_tv.tv_sec = 1; timeout_tv.tv_usec = 0; // 獲取multi curl需要監(jiān)聽的文件描述符集合 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; } /** * 執(zhí)行監(jiān)聽,,當文件描述符狀態(tài)發(fā)生改變的時候返回 * 返回0,,程序調(diào)用curl_multi_perform通知curl執(zhí)行相應操作 * 返回-1,表示select錯誤 * 注意:即使select超時也需要返回0,,具體可以去官網(wǎng)看文檔說明 */ 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 // 這里設(shè)置你需要訪問的url // std::string URL = "http://"; // 這里設(shè)置代理ip和端口 // std::string PROXY = "ip:port"; // 這里設(shè)置超時時間 // 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]; // 設(shè)置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]); } /* * 調(diào)用curl_multi_perform函數(shù)執(zhí)行curl請求 * url_multi_perform返回CURLM_CALL_MULTI_PERFORM時,,表示需要繼續(xù)調(diào)用該函數(shù)直到返回值不是CURLM_CALL_MULTI_PERFORM為止 * running_handles變量返回正在處理的easy curl數(shù)量,,running_handles為0表示當前沒有正在執(zhí)行的curl請求 */ int running_handles; while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles)) { cout << running_handles << endl; } /** * 為了避免循環(huán)調(diào)用curl_multi_perform產(chǎn)生的cpu持續(xù)占用的問題,采用select來監(jiān)聽文件描述符 */ while (running_handles) { if (-1 == curl_multi_select(curl_m)) { cerr << "select error" << endl; break; } else { // select監(jiān)聽到事件,,調(diào)用curl_multi_perform通知curl執(zhí)行相應的操作 // while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles)) { cout << "select: " << running_handles << endl; } } cout << "select: " << running_handles << endl; } // 輸出執(zhí)行結(jié)果 // 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_CURL struct 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 // 獲取結(jié)束時間 // struct timeval end_tv; gettimeofday(&end_tv, NULL); // 計算執(zhí)行延時并輸出,,用于比較 // 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; }
轉(zhuǎn)載自: http://blog.csdn.net/zxgfa/article/details/8220724 |
|