使用libcurl的正確姿勢


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;
        }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM