libcurl主要提供了兩種發送http請求的方式,分別是Easy interface方式和multi interface方式,前者是採用阻塞的方式發送單條數據,後者採用組合的方式能夠一次性發送多條數據mysql
1、Easy interface
sql
libcurl的easy interface是最基本的用法,簡要流程爲:
一、在主線程中調用curl_global_init(CURL_GLOBAL_ALL)初始化
二、調用curl_easy_init獲取一個句柄;
三、調用curl_easy_setopt函數設置這次傳輸的一些基本參數,如url地址、http頭、cookie信息、發送超時時間等,其中,CURLOPT_URL是必設的選項;
四、設置完成後,調用curl_easy_perform函數發送數據;
五、數據發送完畢後,調用curl_easy_cleanup清空句柄;
六、調用curl_global_cleanup()作清理工做。
cookie
實現代碼:多線程
- bool send_easy_hanler(char* post_url, req_t* req)
- {
-
- CURL* curl = NULL;
- CURLcode res = CURLE_OK;
-
- struct curl_slist* headers = NULL;
- char tmp_str[256] = { 0 };
-
-
- snprintf(tmp_str, sizeof(tmp_str), "User-Agent: %s", req->user_agent_);
- headers = curl_slist_append(headers, tmp_str);
- snprintf(tmp_str, sizeof(tmp_str), "Accept-Language: %s", req->language_);
- headers = curl_slist_append(headers, tmp_str);
- snprintf(tmp_str, sizeof(tmp_str), "X-FORWORDED-FOR: %s", req->ip_.c_str());
- headers = curl_slist_append(headers, tmp_str);
-
-
- curl_global_init(CURL_GLOBAL_ALL);
-
-
- curl = curl_easy_init();
- if (curl) {
-
- curl_easy_setopt(curl, CURLOPT_URL, post_url);
-
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
-
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);
-
-
- res = curl_easy_perform(curl);
- if (res != CURLE_OK) {
-
- LOG(WARNING) << "curl_easy_perform() failed:" << curl_easy_strerror(res);
- }
-
- curl_slist_free_all(headers);
-
-
- curl_easy_cleanup(curl);
-
-
- curl_global_cleanup();
- }
2、multi interface
multi interface提供了多種easy interface沒有的特性,主要是
一、提供了pull接口,使用libcurl的程序可以決定什麼時候何處調用libcurl來get/send數據
二、在同一線程中實現多條數據同時發送,且並無使得程序更加複雜
三、程序能夠在本身的文件描述符和curl的文件描述符中同時等待執行
四、提供基於事件的處理、擴大傳輸規模到數千個併發鏈接
multi接口的使用會比easy 接口稍微複雜點,畢竟multi接口是依賴easy接口的,簡要流程爲:
一、使用curl_multi_init建立一個multi handle,這個handler會在後續的curl_multi_*函數中使用multi handler能夠同時併發傳輸多條數據,每一條單獨的數據是由一個easy handler建立;
二、須要事先將須要傳輸的全部easyhandler建立好,並使用curl_easy_setopt設置各自屬性,接着調用curl_multi_add_handle函數逐個添加到multi handle中;
三、調用curl_multi_perform進程數據傳輸,傳輸過程當中將會調用每個easy handler設置的回調函數或者配置內容,程序經過函數curl_multi_fdset、select()提取信息來判斷什麼時候進行數據傳輸等操做,函數curl_multi_perform的一個輸入參數儲存仍在進行傳輸的數據量,經過讀取該變量,能夠判斷multi handles是否運行完畢,傳輸完畢不表明傳輸成功,可能有一個或多個傳輸失敗;
四、調用函數curl_multi_info_read能夠獲取當前或以前傳輸的信息,重複調用該函數直到該消息隊列爲空,每一條返回信息都包含對應的easl handler的傳輸狀況;
五、當一個easy handler傳輸完成,此easy handler仍然仍然停留在multi stack中,須要調用curl_multi_remove_handle將其從multi stack中移除,而後調用curl_easy_cleanup將其關閉;
六、當multi stack中的全部傳輸都完成時,調用 curl_multi_cleanup關閉multi handler,須要注意的是事先要調用curl_easy_cleanup逐個清空全部easy handler。併發
源碼:oracle
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #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",
- };
-
- #define MAX 8 /* number of simultaneous transfers */
- #define CNT sizeof(urls)/sizeof(char*) /* total number of transfers to do */
-
- static size_t cb(char *d, size_t n, size_t l, void *p)
- {
-
- (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;
- CURLMsg *msg;
- long curl_timeo;
- unsigned int C=0;
- int max_fd, msgs_left, still_running = -1;
- fd_set fd_read, fd_write, fd_except;
- struct timeval T;
-
- curl_global_init(CURL_GLOBAL_ALL);
-
- cm = curl_multi_init();
-
-
- curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)MAX);
-
- for(C = 0; C < MAX; ++C) {
- init(cm, C);
- }
-
-
- do{
- curl_multi_perform(cm, &still_running);
-
- if(still_running) {
- FD_ZERO(&fd_read);
- FD_ZERO(&fd_write);
- FD_ZERO(&fd_except);
-
-
- if(!curl_multi_fdset(cm, &fd_read, &fd_write, &fd_except, &max_fd)) {
- fprintf(stderr, "E: curl_multi_fdset\n");
- return EXIT_FAILURE;
- }
-
- if(!curl_multi_timeout(cm, &curl_timeo)) {
- fprintf(stderr, "E: curl_multi_timeout\n");
- return EXIT_FAILURE;
- }
- if(curl_timeo == -1)
- curl_timeo = 100;
-
-
- if(max_fd == -1) {
- sleep((unsigned int)curl_timeo / 1000);
- }
- else {
- T.tv_sec = curl_timeo/1000;
- T.tv_usec = (curl_timeo%1000)*1000;
-
-
- if(0 > select(max_fd+1, &fd_read, &fd_write, &fd_except, &T)) {
- fprintf(stderr, "E: select(%i,,,,%li): %i: %s\n",
- max_fd+1, curl_timeo, errno, strerror(errno));
- return EXIT_FAILURE;
- }
- }
- }
-
- while((msg = curl_multi_info_read(cm, &msgs_left))) {
- 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);
- }
- }
- }while(still_running);
-
-
- curl_multi_cleanup(cm);
- curl_global_cleanup();
-
- return EXIT_SUCCESS;
- }