• libcurl同时下载多个文件


    #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
    ");
            return EXIT_FAILURE;
          }
     
          if(curl_multi_timeout(cm, &L)) {
            fprintf(stderr, "E: curl_multi_timeout
    ");
            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
    ",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>
    ",
                    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)
    ", 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;
    }
    

      

  • 相关阅读:
    没时间写文章::>_<::
    使 iis 支持 flv 视频播放
    CentOS7系统配置国内yum源(阿里云)
    android adb启动失败问题 adb server is out of date. killing... ADB server didn't ACK * failed to start daemon *
    android开发 获取手机分辨率大小
    c++流操作>rdbuf()
    ROR:Mysql ERROR 1045 (28000): Access denied for user 'root'@'localhost'
    android map如何获得Google Map API key
    Android有效解决加载大图片时内存溢出的问题
    Android开发之Intent跳转到系统应用中的拨号界面、联系人界面、短信界面
  • 原文地址:https://www.cnblogs.com/gushandujian/p/6009647.html
Copyright © 2020-2023  润新知