#include <errno.h> #include <stdlib.h> #include <string.h> #ifndef WIN32 #include <unistd.h> #endif #include <curl/multi.h> static const char *urls[] = { "http://www.microsoft.com", "http://www.opensource.org", "http://www.google.com", "http://www.yahoo.com", "http://www.ibm.com", "http://www.mysql.com", "http://www.oracle.com", "http://www.ripe.net", "http://www.iana.org", "http://www.amazon.com", "http://www.netcraft.com", "http://www.heise.de", "http://www.chip.de", "http://www.ca.com", "http://www.cnet.com", "http://www.news.com", "http://www.cnn.com", "http://www.wikipedia.org", "http://www.dell.com", "http://www.hp.com", "http://www.cert.org", "http://www.mit.edu", "http://www.nist.gov" }; #define MAX 10 #define CNT sizeof(urls)/sizeof(char*) 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; } int nIndex=0; 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_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url);查詢出來 curl_easy_setopt(eh, CURLOPT_VERBOSE, 0L); //如果你想CURL報告每一件意外的事情,設置這個選項為一個非零值 curl_easy_setopt(eh, CURLOPT_WRITEDATA, (void *)&nIndex); //設置調用cb函數時傳遞cb函數的第四個參數 curl_easy_setopt(eh, CURLOPT_USERAGENT, "Lavf/55.13.102"); //設置useragent curl_multi_add_handle(cm, eh); } int main(void) { CURLM *cm; CURLMsg *msg; long L; unsigned int C=0; int M, Q, U = -1; fd_set R, W, E; struct timeval T; curl_global_init(CURL_GLOBAL_ALL); cm = curl_multi_init(); /* we can optionally limit the total amount of connections this multi handle uses */ curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)MAX); for(C = 0; C < MAX; ++C) { init(cm, C); } while(U) { curl_multi_perform(cm, &U); //執行並發請求,非阻塞,立即返回 if(U) { FD_ZERO(&R); FD_ZERO(&W); FD_ZERO(&E); //獲取cm需要監聽的文件描述符集合,如果返回的M等於-1,需要等一會然后再次調用curl_multi_perform,等多久?建議至少100毫秒,但你可能想在你自己的特定條件下測試它,找到一個合適的值 if(curl_multi_fdset(cm, &R, &W, &E, &M)) { fprintf(stderr, "E: curl_multi_fdset\n"); return EXIT_FAILURE; } if(curl_multi_timeout(cm, &L)) { fprintf(stderr, "E: curl_multi_timeout\n"); return EXIT_FAILURE; } if(L == -1) L = 100; if(M == -1) { #ifdef WIN32 Sleep(L); #else sleep((unsigned int)L / 1000); #endif } else { T.tv_sec = L/1000; T.tv_usec = (L%1000)*1000; /*確定一個或多個套接口的狀態,可查詢它的可讀性、可寫性及錯誤狀態信息。 返回值: select()調用返回處於就緒狀態並且已經包含在fd_set結構中的描述字總數;如果超時則返回0;否則的話,返回SOCKET_ERROR(-1)錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。 */ if(0 > select(M+1, &R, &W, &E, &T)) { fprintf(stderr, "E: select(%i,,,,%li): %i: %s\n",M+1, L, errno, strerror(errno)); return EXIT_FAILURE; } } } /*獲取當前解析的cURL的相關傳輸信息 查詢批處理句柄是否單獨的傳輸線程中有消息或信息返回。消息可能包含諸如從單獨的傳輸線程返回的錯誤碼或者只是傳輸線程有沒有完成之類的報告。 重復調用這個函數,它每次都會返回一個新的結果,直到這時沒有更多信息返回時,FALSE 被當作一個信號返回。通過msgs_in_queue返回的整數指出將會包含當這次函數被調用后,還剩余的消息數。 Warning 返回的資源指向的數據調用curl_multi_remove_handle()后將不會存在。 */ while((msg = curl_multi_info_read(cm, &Q))) { if(msg->msg == CURLMSG_DONE) { char *url; CURL *e = msg->easy_handle; curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url); fprintf(stderr, "R: %d - %s <%s>\n", msg->data.result, curl_easy_strerror(msg->data.result), url); curl_multi_remove_handle(cm, e); curl_easy_cleanup(e); } else { fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg); } if(C < CNT) { init(cm, C++); U++; /* just to prevent it from remaining at 0 if there are more URLs to get */ } } } curl_multi_cleanup(cm); curl_global_cleanup(); return EXIT_SUCCESS; }