Libcurl笔记二

一: 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设置的超时时间。

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毫秒,但是可以根据自己的特殊环境尝试设置一个合适的等待时间。

三:
multi是依赖easy接口的。
步凑:
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对象。

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <curl/curl.h>
  4
  5 /* This is a simple example showing how to fetch mail using libcurl‘s IMAP
  6 * capabilities. It builds on the imap-fetch.c example to demonstrate how to
  7 * use libcurl‘s multi interface.
  8 *
  9 * Note that this example requires libcurl 7.30.0 or above.
 10 */
 11
 12 #define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000
 13
 14 static struct timeval tvnow(void)
 15 {
 16     struct timeval now;
 17
 18     /* time() returns the value of time in seconds since the epoch */
 19     now.tv_sec = (long)time(NULL);
 20     now.tv_usec = 0;
 21
 22     return now;
 23 }
 24
 25 static long tvdiff(struct timeval newer, struct timeval older)
 26 {
 27     return (newer.tv_sec - older.tv_sec) * 1000 +
 28         (newer.tv_usec - older.tv_usec) / 1000;
 29 }
 30
 31 int main(void)
 32 {
 33     CURL *curl;
 34     CURLM *mcurl;
 35     int still_running = 1;
 36     struct timeval mp_start;
 37
 38     curl_global_init(CURL_GLOBAL_DEFAULT);
 39
 40     curl = curl_easy_init();
 41     if(!curl)
 42         return 1;
 43
 44     mcurl = curl_multi_init();
 45     if(!mcurl)
 46         return 2;
 47
 48     /* Set username and password */
 49     curl_easy_setopt(curl, CURLOPT_USERNAME, "user");
 50     curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret");
 51
 52     /* This will fetch message 1 from the user‘s inbox */
 53     curl_easy_setopt(curl, CURLOPT_URL, "imap://imap.example.com/INBOX/;UID=1");
 54
 55     /* Tell the multi stack about our easy handle */
 56     curl_multi_add_handle(mcurl, curl);
 57
 58     /* Record the start time which we can use later */
 59     mp_start = tvnow();
 60
 61     /* We start some action by calling perform right away */
 62     curl_multi_perform(mcurl, &still_running);
 63
 64     while(still_running) {
 65         struct timeval timeout;
 66         fd_set fdread;
 67         fd_set fdwrite;
 68         fd_set fdexcep;
 69         int maxfd = -1;
 70         int rc;
 71         CURLMcode mc; /* curl_multi_fdset() return code */
 72
 73         long curl_timeo = -1;
 74
 75         /* Initialise the file descriptors */
 76         FD_ZERO(&fdread);
 77         FD_ZERO(&fdwrite);
 78         FD_ZERO(&fdexcep);
 79
 80         /* Set a suitable timeout to play around with */
 81         timeout.tv_sec = 1;
 82         timeout.tv_usec = 0;
 83
 84         curl_multi_timeout(mcurl, &curl_timeo);
 85         if(curl_timeo >= 0) {
 86             timeout.tv_sec = curl_timeo / 1000;
 87             if(timeout.tv_sec > 1)
 88                 timeout.tv_sec = 1;
 89             else
 90                 timeout.tv_usec = (curl_timeo % 1000) * 1000;
 91         }
 92
 93         /* get file descriptors from the transfers */
 94         mc = curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
 95
 96         if(mc != CURLM_OK) {
 97             fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
 98             break;
 99         }
100
101         /* On success the value of maxfd is guaranteed to be >= -1. We call
102         select(maxfd + 1, ...); specially in case of (maxfd == -1) there are
103         no fds ready yet so we call select(0, ...) --or Sleep() on Windows--
104         to sleep 100ms, which is the minimum suggested value in the
105         curl_multi_fdset() doc. */
106
107         if(maxfd == -1) {
108 #ifdef _WIN32
109             Sleep(100);
110             rc = 0;
111 #else
112             /* Portable sleep for platforms other than Windows. */
113             struct timeval wait = { 0, 100 * 1000 }; /* 100ms */
114             rc = select(0, NULL, NULL, NULL, &wait);
115 #endif
116         }
117         else {
118             /* Note that on some platforms ‘timeout‘ may be modified by select().
119             If you need access to the original value save a copy beforehand. */
120             rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
121         }
122
123         if(tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) {
124             fprintf(stderr,
125                 "ABORTING: Since it seems that we would have run forever.\n");
126             break;
127         }
128
129         switch(rc) {
130     case -1:  /* select error */
131         break;
132     case 0:   /* timeout */
133     default:  /* action */
134         curl_multi_perform(mcurl, &still_running);
135         break;
136         }
137     }
138
139     /* Always cleanup */
140     curl_multi_remove_handle(mcurl, curl);
141     curl_multi_cleanup(mcurl);
142     curl_easy_cleanup(curl);
143     curl_global_cleanup();
144
145     return 0;
146 }

时间: 2024-12-22 22:36:31

Libcurl笔记二的相关文章

老男孩培训视频听课笔记二(在51cto上听的)

centos 5.8 文本安装过程    引导采用默认,引导不用设置密码    网络配置,根据实际情况配置,网关是网络出口的地址,一般为wlan出口的路由器的地址或者是代理服务器的内网IP    DNS简单解说图:      主机名--时区--root密码    选择自定义系统安装包--最小化(安全方便工作,建议安装以下的组)      ·base-- 基础      ·editors-编辑器      ·development librarays--开发库      ·development

《卓有成效的程序员》----读书笔记二

六大方面对比Launchy和TypeAndRun(TAR) 对于快速启动工具,很多人都有自己的偏好,多次听到朋友介绍Launchy的好,虽然自己一直在使用着TAR,还是克制不住对于好软件的渴求,下载Launchy进行试用.很多软件都是有一个试用期的,也许新的软件确实不错,但是你习惯了以前使用的那个软件.今天就比较客观的将Launchy和TAR进行一下对比,从界面.上手速度到功能.自定义,以及软件的稳定性.占用资源进行详细的比较. [界面美观]Launchy:毫无疑问这是它的强项.1.0正式版自带

Caliburn.Micro学习笔记(二)----Actions

Caliburn.Micro学习笔记(二)----Actions 上一篇已经简单说了一下引导类和简单的控件绑定 我的上一个例子里的button自动匹配到ViewModel事件你一定感觉很好玩吧 今天说一下它的Actions,看一下Caliburn.Micro给我们提供了多强大的支持 我们还是从做例子开始 demo的源码下载在文章的最后 例子1.无参数方法调用 点击button把textBox输入的文本弹出来 如果textbox里没有文本button不可点,看一下效果图 看一下前台代码 <Stac

《逻辑思维简易入门》(第2版) 阅读笔记二

<逻辑思维简易入门>(第2版) 阅读笔记二 本周阅读的是<逻辑思维简易入门>的第三章,也就是说,本书的第一部分就已经读完了. 第三章.信念的优点 信念和负信念是人们在接受一个事物时一种心理态度,延伸来说也就是对事物的认知态度.因为我们在研究 逻辑思维的时候,都有一个前提:“以正常情况以及说话者真诚”,所以有人如果对于一件事物不做回应,我们可以认为这是一种既不相信,也不怀疑的的态度. 信念的优缺点有很多,在书中主要介绍了下面几种: 1.准确性 好的信念实在准确的表达事实,同样真的信念

2. 蛤蟆Python脚本学习笔记二基本命令畅玩

2. 蛤蟆Python脚本学习笔记二基本命令畅玩 本篇名言:"成功源于发现细节,没有细节就没有机遇,留心细节意味着创造机遇.一件司空见惯的小事或许就可能是打开机遇宝库的钥匙!" 下班回家,咱先来看下一些常用的基本命令. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/48092873 1.  数字和表达式 看下图1一就能说明很多问题: 加法,整除,浮点除,取模,幂乘方等.是不是很直接也很粗暴. 关于上限,蛤蟆不太清楚

Emacs 笔记二

Emacs 笔记二 Table of Contents 1. 前言 2. emacs基本操作(常用快捷键) 3. emacs模式讲解 4. emacs缓冲区 5. org mode 5.1. 列表 5.2. 快键键 5.3. 内嵌元素(插入代码什么的) 5.4. 表格 1 前言 最近在学着写博客,发现MarkDown真乃神器,于是去找了很多markdown的工具,发现作业部落 最好的那个,而无意间又发现了org-mode火爆到极致 非常被人推崇,其实作业部落 已经是能很完美的满足我的需求了,但是

《Programming in Lua 3》读书笔记(二十二)

日期:2014.8.6 PartⅣ The C API 26 Extending Your Application 使用Lua很重要的一点是用来做配置语言.配合主语言做一些功能的配置. 26.1 The Basics 有的时候程序需要配置一些功能信息,很多时候可能有许多别的方法比用lua做配置要更简单:如使用环境变量或者读取文件,读取文件涉及到文件的解析.如果使用Lua进行配置的话,相当于用lua文件替代了要读取的如csv.txt文件等. 使用Lua进行配置的时候,就需要使用Lua API去控制

小猪的数据结构学习笔记(二)

小猪的数据结构学习笔记(二) 线性表中的顺序表 本节引言: 在上个章节中,我们对数据结构与算法的相关概念进行了了解,知道数据结构的 逻辑结构与物理结构的区别,算法的特性以及设计要求;还学了如何去衡量一个算法 的好坏,以及时间复杂度的计算!在本节中我们将接触第一个数据结构--线性表; 而线性表有两种表现形式,分别是顺序表和链表;学好这一章很重要,是学习后面的基石; 这一节我们会重点学习下顺序表,在这里给大家一个忠告,学编程切忌眼高手低,看懂不代表自己 写得出来,给出的实现代码,自己要理解思路,自己

JavaScript--基于对象的脚本语言学习笔记(二)

第二部分:DOM编程 1.文档象模型(DOM)提供了访问结构化文档的一种方式,很多语言自己的DOM解析器. DOM解析器就是完成结构化文档和DOM树之间的转换关系. DOM解析器解析结构化文档:将磁盘上的结构化文档转换成内存中的DOM树 从DOM树输出结构化文档:将内存中的DOM树转换成磁盘上的结构化文档 2.DOM模型扩展了HTML元素,为几乎所有的HTML元素都新增了innerHTML属性,该属性代表该元素的"内容",即返回的某个元素的开始标签.结束标签之间的字符串内容(不包含其它