libcurl支持訪問http、ftp等各種服務器,下載圖片AV什么的不在話下。但其存在多種接口,異步接口也很難以理解,到底什么樣的使用姿勢才是正確滴?我們來看看可用的體位:
- easy interface:最簡單的同步接口,容易理解,但同步訪問實在不是性能之選。至於引入多線程,那是簡單問題復雜化。注意異步訪問也是以easy interface為基礎,所以還是要學習一下:《libcurl教程》。
- multi interface:異步訪問接口,性能杠杠滴,但是。。。真的很難理解啊。。。官方文檔:《multi interface overview》。
-
curl_multi_perform() + select():select()性能不夠好,還受到file descriptors不能大於1024的限制。參考《使用libcurl進行異步並發訪問與文件上傳》。
-
curl_multi_socket_action():使用epoll模型,性能最好,但更難懂。。。參考范例。
-
curl_multi_perform() + curl_multi_wait():這個據說是facebook做出的偉大貢獻(參見《Introducing curl_multi_wait》),保證性能的同時也相對容易使用,強力推薦的姿勢。抄錄示例代碼如下:
/* curl_multi_test.c Clemens Gruber, 2013 <clemens.gruber@pqgruber.com> Code description: Requests 4 Web pages via the CURL multi interface and checks if the HTTP status code is 200. Update: Fixed! The check for !numfds was the problem. */ #include <stdio.h> #include <stdlib.h> #ifndef WIN32 #include <unistd.h> #endif #include <curl/multi.h> #define MAX_WAIT_MSECS 30*1000 /* Wait max. 30 seconds */ static const char *urls[] = { "http://www.microsoft.com", "http://www.yahoo.com", "http://www.wikipedia.org", "http://slashdot.org" }; #define CNT 4 static size_t cb(char *d, size_t n, size_t l, void *p) { /* take care of the data here, ignored in this example */ (void)d; (void)p; return n*l; } static void init(CURLM *cm, int i) { CURL *eh = curl_easy_init(); curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, cb); curl_easy_setopt(eh, CURLOPT_HEADER, 0L); curl_easy_setopt(eh, CURLOPT_URL, urls[i]); curl_easy_setopt(eh, CURLOPT_PRIVATE, urls[i]); curl_easy_setopt(eh, CURLOPT_VERBOSE, 0L); curl_multi_add_handle(cm, eh); } int main(void) { CURLM *cm=NULL; CURL *eh=NULL; CURLMsg *msg=NULL; CURLcode return_code=0; int still_running=0, i=0, msgs_left=0; int http_status_code; const char *szUrl; curl_global_init(CURL_GLOBAL_ALL); cm = curl_multi_init(); for (i = 0; i < CNT; ++i) { init(cm, i); } curl_multi_perform(cm, &still_running); do { int numfds=0; int res = curl_multi_wait(cm, NULL, 0, MAX_WAIT_MSECS, &numfds); if(res != CURLM_OK) { fprintf(stderr, "error: curl_multi_wait() returned %d\n", res); return EXIT_FAILURE; } /* if(!numfds) { fprintf(stderr, "error: curl_multi_wait() numfds=%d\n", numfds); return EXIT_FAILURE; } */ curl_multi_perform(cm, &still_running); } while(still_running); while ((msg = curl_multi_info_read(cm, &msgs_left))) { if (msg->msg == CURLMSG_DONE) { eh = msg->easy_handle; return_code = msg->data.result; if(return_code!=CURLE_OK) { fprintf(stderr, "CURL error code: %d\n", msg->data.result); continue; } // Get HTTP status code http_status_code=0; szUrl = NULL; curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, &http_status_code); curl_easy_getinfo(eh, CURLINFO_PRIVATE, &szUrl); if(http_status_code==200) { printf("200 OK for %s\n", szUrl); } else { fprintf(stderr, "GET of %s returned http status code %d\n", szUrl, http_status_code); } curl_multi_remove_handle(cm, eh); curl_easy_cleanup(eh); } else { fprintf(stderr, "error: after curl_multi_info_read(), CURLMsg=%d\n", msg->msg); } } curl_multi_cleanup(cm); return EXIT_SUCCESS; }
-
