一: multi与easy接口的不同处
The multi interface offers several abilities that the easy interface doesn't. They are mainly:
1. Enable a "pull" interface. The application that uses libcurl decides where and when to ask libcurl to get/send data.
2. Enable multiple simultaneous transfers in the same thread without making it complicated for the application.
3. Enable the application to wait for action on its own file descriptors and curl's file descriptors simultaneous easily.
4. Enable event-based handling and scaling transfers up to and beyond thousands of parallel connections.

在收发数据的时候能后取消操作。
在一个线程里同时多个传输操作而不造成混乱。
应用程序能够同时等待它自己 和curl的文件描述符(句柄)。
能基于事件处理和传输超过数千个的并行链接。

二:
1,
CURLM *curl_multi_init( );
CURLMcode curl_multi_cleanup( CURLM *multi_handle ); With a multi handle and the multi interface you can do several simultaneous transfers in parallel.
Each single transfer is built up around an easy handle.
You create all the easy handles you need, and setup the appropriate options for each easy handle using curl_easy_setopt.
multi支持同时多文件并发传输。
单文件传输请用easy接口。
使用easy接口都需要setopt设置相应参数。 When an easy handle is setup and ready for transfer, then instead of using curl_easy_perform like when using the easy interface for transfers, you should add the easy handle to the multi handle with curl_multi_add_handle. You can add more easy handles to a multi handle at any point, even if other transfers are already running.
当设置好easy模式并准备传输的时候,可以使用curl_multi_add_handle替代curl_easy_perform。
能在任何时候增加一个esay模式句柄给multi模式,及时easy已经在执行传输操作了 Should you change your mind, the easy handle is again removed from the multi stack using curl_multi_remove_handle. Once removed from the multi handle, you can again use other easy interface functions like curl_easy_perform on the handle or whatever you think is necessary. You can remove handles at any point in time during transfers.
可以在任何时候从multi栈中移出,一旦移出可以再次使用curl_easy_perform。 Adding the easy handle to the multi handle does not start the transfer. Remember that one of the main ideas with this interface is to let your application drive. You drive the transfers by invoking curl_multi_perform. libcurl will then transfer data if there is anything available to transfer. It'll use the callbacks and everything else you have setup in the individual easy handles. It'll transfer data on all current transfers in the multi stack that are ready to transfer anything. It may be all, it may be none. When there's nothing more to do for now, it returns back to the calling application.
添加easy句柄到multi并不马上开始执行,由curl_multi_perform启动执行。
启动后将执行所有multi stack中的收发事件。如果栈上是空的直接返回。 2,
CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles);
running_handles返回multi栈里仍需执行的句柄数。
If the amount of running_handles is changed from the previous call (or is less than the amount of easy handles you've added to the multi handle), you know that there is one or more transfers less "running". You can then call curl_multi_info_read to get information about each individual completed transfer, and that returned info includes CURLcode and more. If an added handle fails very quickly, it may never be counted as a running_handle.
如果running_handles的值比增加到multi栈时少了,就是有一些传输操作执行完了。你能调用curl_multi_info_read获取每一个执行完成的操作信息。如果添加立即失败,它不会被算入running_handles。
/* call curl_multi_perform or curl_multi_socket_action first, then loop
  through and check if there are any transfers that have completed */
struct CURLMsg *m;
do {
  int msgq = 0;
  m = curl_multi_info_read(multi_handle, &msgq);
  if(m && (m->msg == CURLMSG_DONE)) {
  CURL *e = m->easy_handle;
  transfers--;
  curl_multi_remove_handle(multi_handle, e);
  curl_easy_cleanup(e);
  }
} while(m); 3,
Your application extracts info from libcurl about when it would like to get invoked to transfer data or do other work. The most convenient way is to use curl_multi_wait that will help you wait until the application should call libcurl again. The older API to accomplish the same thing is curl_multi_fdset that extracts fd_sets from libcurl to use in select() or poll() calls in order to get to know when the transfers in the multi stack might need attention. Both these APIs allow for your program to wait for input on your own private file descriptors at the same time curl_multi_timeout also helps you with providing a suitable timeout period for your select() calls.
你的程序可以在libcurl正工作的时候获取一些信息。
通常使用curl_multi_wait等待直到线程被libcurl唤起。老的api使用curl_multi_fdset设置 select或者poll模型触发。
等待这些api返回的同时可以使用curl_multi_timeout获取一个为select设置的超时时间。 curl_multi_wait polls all file descriptors used by the curl easy handles contained in the given multi handle set. It will block until activity is detected on at least one of the handles or timeout_ms has passed. Alternatively, if the multi handle has a pending internal timeout that has a shorter expiry time than timeout_ms, that shorter time will be used instead to make sure timeout accuracy is reasonably kept.
The calling application may pass additional curl_waitfd structures which are similar to poll(2)'s pollfd structure to be waited on in the same call.
On completion, if numfds is non-NULL, it will be populated with the total number of file descriptors on which interesting events occurred. This number can include both libcurl internal descriptors as well as descriptors provided in extra_fds
curl_multi_wait轮询multi上的所有easy句柄,一直阻塞直到至少有一个被触发或者超时。
如果multi句柄正因为网络延时而挂起,会有一个更短更精确的时间来代替我们自己设置的超时时间timeout_ms。
curl_waitfd数组怎加需要监听的socket。
wait返回后,numfds讲返回被触发的事件数量,若为0表示超时或者没有事件等待。numfds的值包括multi栈上的和extra_fds新加的之和。
CURLMcode curl_multi_wait(CURLM *multi_handle,

struct curl_waitfd extra_fds[],

unsigned int extra_nfds,

int timeout_ms,

int *numfds);

CURLMcode curl_multi_timeout(CURLM *multi_handle, long *timeout);
An application using the libcurl multi interface should call curl_multi_timeout to figure out how long it should wait for socket actions - at most - before proceeding.
一个使用了multi接口的程序应该用url_multi_timeout来预估出在程序激活前最少应该等在socket事件多长时间。
The timeout value returned in the long timeout points to, is in number of milliseconds at this very moment. If 0, it means you should proceed immediately without waiting for anything. If it returns -1, there's no timeout at all set.
第二个指针参数timeout获取毫秒的超时等待时间,如果为0表示没有等待继续做一些事情,如果为-1表示所有都没设置超时时间。
struct timeval timeout;

long timeo;
 
curl_multi_timeout(multi_handle, &timeo);
if(timeo < 0)
  timeo = 980;// no set timeout, use a default
 
timeout.tv_sec = timeo / 1000;
timeout.tv_usec = (timeo % 1000) * 1000;
select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);// wait for activities no longer than the set timeout CURLMcode curl_multi_fdset(CURLM *multi_handle,
                           fd_set *read_fd_set,
                           fd_set *write_fd_set,
                           fd_set *exc_fd_set,
                           int *max_fd);

获取可以读写或有错误的集合。
If no file descriptors are set by libcurl, max_fd will contain -1 when this function returns. Otherwise it will contain the highest descriptor number libcurl set. When libcurl returns -1 in max_fd, it is because libcurl currently does something that isn't possible for your application to monitor with a socket and unfortunately you can then not know exactly when the current action is completed using select(). You then need to wait a while before you proceed and call curl_multi_perform anyway. How long to wait? We suggest 100 milliseconds at least, but you may want to test it out in your own particular conditions to find a suitable value.
如果sd_set都没被libcurl设置,这函数返回时max_fd值为-1。否则,max_fd为fd_set里被触发的最大个数。
如果max_fd为-1可能是应为程序正在监听一个socket的时候libcurl当前什么也不能不了;并且很不幸此时你不能知道select何时完事。因此执行curl_multi_perform前需要等待一段时间,建议100毫秒,但是可以根据自己的特殊环境尝试设置一个合适的等待时间。

三:
1,
multi是依赖easy接口的。

2,
步凑:
curl_multi _init初始化一个multi curl对象,
为了同时进行多个curl的并发访问,需要初始化多个easy curl对象,使用curl_easy_setopt进行相关设置,
然后调用curl_multi _add_handle把easy curl对象添加到multi curl对象中,
添加完毕后执行curl_multi_perform方法进行并发的访问,
访问结束后curl_multi_remove_handle移除相关easy curl对象,
curl_easy_cleanup清除easy curl对象,
最后curl_multi_cleanup清除multi curl对象。

3,

#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* This is a simple example showing how to fetch mail using libcurl's IMAP
* capabilities. It builds on the imap-fetch.c example to demonstrate how to
* use libcurl's multi interface.
*
* Note that this example requires libcurl 7.30.0 or above.
*/ #define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 static struct timeval tvnow(void)
{
struct timeval now;
/* time() returns the value of time in seconds since the epoch */
now.tv_sec = (long)time(NULL);
now.tv_usec = ; return now;
} static long tvdiff(struct timeval newer, struct timeval older)
{
return (newer.tv_sec - older.tv_sec) * +
(newer.tv_usec - older.tv_usec) / ;
} int main(void)
{
CURL *curl;
CURLM *mcurl;
int still_running = ;
struct timeval mp_start; curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init()
if (!curl)
return ; mcurl = curl_multi_init();
if (!mcurl)
return ; /* Set username and password */
curl_easy_setopt(curl, CURLOPT_USERNAME, "user");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret"); /* This will fetch message 1 from the user's inbox */
curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com/INBOX/;UID=1"); /* Tell the multi stack about our easy handle */
curl_multi_add_handle(mcurl, curl); /* Record the start time which we can use later */
mp_start = tvnow(); /* We start some action by calling perform right away */
curl_multi_perform(mcurl, &still_running); while (still_running) {
struct timeval timeout;
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd = -;
int rc;
CURLMcode mc; /* curl_multi_fdset() return code */
long curl_timeo = -; /* Initialise the file descriptors */
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep); /* Set a suitable timeout to play around with */
timeout.tv_sec = ;
timeout.tv_usec = ; curl_multi_timeout(mcurl, &curl_timeo);
if (curl_timeo >= ) {
timeout.tv_sec = curl_timeo / ;
if (timeout.tv_sec > )
timeout.tv_sec = ;
else
timeout.tv_usec = (curl_timeo % ) * ;
} /* get file descriptors from the transfers */
mc = curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
if (mc != CURLM_OK) {
fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
break;
} /* On success the value of maxfd is guaranteed to be >= -1. We call
select(maxfd + 1, ...); specially in case of (maxfd == -1) there are
no fds ready yet so we call select(0, ...) --or Sleep() on Windows--
to sleep 100ms, which is the minimum suggested value in the
curl_multi_fdset() doc. */ if (maxfd == -) {
#ifdef _WIN32
Sleep();
rc = ;
#else
/* Portable sleep for platforms other than Windows. */
struct timeval wait = { , * }; /* 100ms */
rc = select(, NULL, NULL, NULL, &wait);
#endif
}
else {
/* Note that on some platforms 'timeout' may be modified by select().
If you need access to the original value save a copy beforehand. */
rc = select(maxfd + , &fdread, &fdwrite, &fdexcep, &timeout);
} if (tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) {
fprintf(stderr,
"ABORTING: Since it seems that we would have run forever.\n");
break;
} switch (rc) {
case -: /* select error */
break;
case : /* timeout */
default: /* action */
curl_multi_perform(mcurl, &still_running);
break;
}
} /* Always cleanup */
curl_multi_remove_handle(mcurl, curl);
curl_multi_cleanup(mcurl);
curl_easy_cleanup(curl);
curl_global_cleanup(); return ;
}

Libcurl笔记二的更多相关文章

  1. 《CMake实践》笔记二:INSTALL/CMAKE_INSTALL_PREFIX

    <CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...

  2. jQuery源码笔记(二):定义了一些变量和函数 jQuery = function(){}

    笔记(二)也分为三部分: 一. 介绍: 注释说明:v2.0.3版本.Sizzle选择器.MIT软件许可注释中的#的信息索引.查询地址(英文版)匿名函数自执行:window参数及undefined参数意 ...

  3. Mastering Web Application Development with AngularJS 读书笔记(二)

    第一章笔记 (二) 一.scopes的层级和事件系统(the eventing system) 在层级中管理的scopes可以被用做事件总线.AngularJS 允许我们去传播已经命名的事件用一种有效 ...

  4. Python 学习笔记二

    笔记二 :print 以及基本文件操作 笔记一已取消置顶链接地址 http://www.cnblogs.com/dzzy/p/5140899.html 暑假只是快速过了一遍python ,现在起开始仔 ...

  5. WPF的Binding学习笔记(二)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

  6. webpy使用笔记(二) session/sessionid的使用

    webpy使用笔记(二) session的使用 webpy使用系列之session的使用,虽然工作中使用的是django,但是自己并不喜欢那种大而全的东西~什么都给你准备好了,自己好像一个机器人一样赶 ...

  7. AJax 学习笔记二(onreadystatechange的作用)

    AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...

  8. 《MFC游戏开发》笔记二 建立工程、调整窗口

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/9300383 作者:七十一雾央 新浪微博:http:/ ...

  9. JavaScript基础笔记二

    一.函数返回值1.什么是函数返回值    函数的执行结果2. 可以没有return // 没有return或者return后面为空则会返回undefined3.一个函数应该只返回一种类型的值 二.可变 ...

随机推荐

  1. 用VS2010开发Android应用的配置方法

    在开发你的第一个Android应用程序之前,你应该先检查一下是否安装了Android SDK,以及是否创建好了Android模拟器(AVD),如果有不清楚的地方,请先看百度这篇文章“Android是什 ...

  2. VBA Excel 打印

    1. 设置 页边距.打印区域 With .PageSetup .HeaderMargin = Application.CentimetersToPoints(0.5) .LeftMargin = Ap ...

  3. u检验、t检验、F检验、X2检验 (转)

    http://blog.renren.com/share/223170925/14708690013 常用显著性检验 1.t检验 适用于计量资料.正态分布.方差具有齐性的两组间小样本比较.包括配对资料 ...

  4. Linux vi编辑器

    vim在内存缓冲区中处理数据 如果在启动vim时未指定文件名,或者这个文件不存在,vim会新开一段缓冲区来编辑. h 左移一个字符 j 下移一行 k 上移一行 l 右边移一个字符 PageDown(C ...

  5. 小白日记7:kali渗透测试之主动信息收集-发现(一)--二层发现:arping/shell脚本,Netdiscover,scapy

    主动信息收集 被动信息收集可能不准确,可以用主动信息收集验证   特点:直接与目标系统交互通信,无法避免留下访问痕迹 解决方法:1.使用受控的第三方电脑进行探测,使用代理 (做好被封杀的准备)   2 ...

  6. javascript 通过面向对象编写圆形数字时钟

    效果如图所示,代码如下 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  7. php实现MVC

    在PHP中使用MVC越来越流行了,特别是在一些开源的框架当中.MVC足以应对大多数的情况,但还有一些情况是其不太适合的,如比较简单的个人博客,对于只有几百篇文章量级的博客,使用MVC让人觉得有些太复杂 ...

  8. spl_autoload_register()和__autoload()区别

    这篇文章主要介绍了spl_autoload_register()和__autoload()区别,需要的朋友可以参考下   关于spl_autoload_register()和__autoload(), ...

  9. 【二分查找最优解】FZU 2056 最大正方形

    题意:现在有一个n*m的矩阵A,在A中找一个H*H的正方形,使得其面积最大且该正方形元素的和不大于 limit. 分析:开始以为是DP或者二维RMQ,其实用二分就可以做出来: 在输入时构造元素和矩阵d ...

  10. 【BZOJ1212】[HNOI2004]L语言 Trie树

    [BZOJ1212][HNOI2004]L语言 Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构 ...