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

  

时间: 2024-10-18 08:19:23

libcurl同时下载多个文件的相关文章

ftp下载指定日期文件(文件名中含日期)

网上查了很多,但是执行都各种错误,然后自己研究了半天,整了个能用的 要求:FTP文件名中含日期 步骤:将一下代码保存为BAT脚本,配置定时任务即可 @echo offrem 计算指定天数之前的日期set DaysAgo=1rem 假设系统日期的格式为yyyy-mm-ddcall :DateToDays %date:~0,4% %date:~5,2% %date:~8,2% PassDaysset /a PassDays-=%DaysAgo%call :DaysToDate %PassDays%

Internet Explorer 浏览器在同一时刻只能从同一域名下载两个文件。

Internet Explorer 浏览器在同一时刻只能从同一域名下载两个文件.至于原因请见 MSDN Blogs:<Internet Explorer and Connection Limits>,如何解除限制请见微软客户帮助与支持主页:<如何将 Internet Explorer 配置为可以同时进行两个以上的下载会话>.不管 Firefox 有多火,无可否认,IE 仍然是浏览器市场的老大.所以,在做系统架构时,不得不去考虑 IE  同时只能从同一域名下载两个文件的限制.如果超过

如何下载远程dll文件,并且执行不被360报毒

当然,说的是没有数字签名的情况,如果有数字签名一切都好说. 正常情况下载一个dll到本地,执行肯定会被360报毒的. 我的方法,主要有以下几点: 1 文件一定要加密,哪怕是只有抑或一下简单的加密. 2 要手动加载dll,不要用系统的LoadLibrary. 这样360就认为你只是下载一个普通文件,不会报毒啦,一个小例子,放在百度网盘了 pan.baidu.com/s/1ntH0IrJ 需要的代码很简单,手动加载dll百度有很多例子,实在需要代码请加微信公众号,私信我. 欢迎关注 windows驱

php一次下载多个文件记载

客户要求将现在的单个下载改成打包下载,正常思路就是将文件临时保存起来再打个压缩包下载,搞了很多天,没搞出来,有2个难题: 1.原来保存的文件为tmp格式,怎样转成xls或xlsx正常的格式. 2.将文件压成zip包之后打不开,总报错. 我只能暂时放弃,找了一个折中的方法.就是将单个文件for循环下载,但由于html自身的限制,下载一个就会停止. 在这感谢网友geel的提醒,最后解决了这个问题. 通过for循环,重新访问文件生成页面,window.open.这才解决了这个问题. 不过这样做还是有个

linux批量下载FTP服务器文件

由于在vmwarem内做一个ORACLE测试环境,要从宿主机上复制ORACLE源安装文件.方法有很多,这次就想用3cdaemon把宿主机(windows)做TFTP服务器端,LINUX做客户端下载的方式实现.居然没那么容易. 1.用FTP登录,发现get只能下载单个文件,mget可以下载多个文件,但不能下载目录!没法下载几个G大小N个子目录的文件啊. 2.wget -r -nH --ftp-user=username --ftp-password=password 如:wget -r -nH f

Ubuntu安装已经下载好的文件包

默认的文件下载都在 ~/Downloads 文件夹里面. 按 ctrl+alt+t 打开命令. 1.解压下载好的文件包,如: tar -xvf Sublime\ Text\ 2.0.2.tar.bz2 2.将解压出来的文件移到 /usr/local/lib/ 目录里面: mv Sublime\ Text\ 2 /usr/local/lib/ 3.再给它建立一个快捷方式(类似与windows中的快捷方式,实际是一个链接),这样,在Terminal的任意地方都可以随心所欲的打开sublime tex

Ant步步为营(2)在ftp上下载需要的文件

早上好,开始一天工作之前先踩踩了园子,今天介绍ftp上下载文件. <?xml version="1.0"?>    <project name="ForTest" default="ftp.download" >    <property file="build.properties"></property>        <target name= "ftp.d

Android连接socket服务器上传下载多个文件

android连接socket服务器上传下载多个文件1.socket服务端SocketServer.java public class SocketServer { int port = 8888;// 端口号,必须与客户端一致 // 选择进行传输的文件(测试) String path = "C:\\Temp"; String filePath = "E:\\img.png"; Socket client; public static void main(Strin

aspx 文件上传和下载,多文件上传

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="MultiFileUpload.aspx.cs"  Inherits="MultiFileUpload"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org