c语言libcurl库的异步用法
multi接口的使用会比easy 接口稍微复杂点,毕竟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对象。
#include <string>
#include <iostream> #include <curl/curl.h>
#include <sys/time.h>
#include <unistd.h> using namespace std; size_t curl_writer(void *buffer, size_t size, size_t count, void * stream)
{
std::string * pStream = static_cast<std::string *>(stream);
(*pStream).append((char *)buffer, size * count); return size * count;
}; /**
* 生成一个easy curl对象,进行一些简单的设置操作
*/
CURL * curl_easy_handler(const std::string & sUrl,
const std::string & sProxy,
std::string & sRsp,
unsigned int uiTimeout)
{
CURL * curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, sUrl.c_str());
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, ); if (uiTimeout > )
{
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, uiTimeout);
}
if (!sProxy.empty())
{
curl_easy_setopt(curl, CURLOPT_PROXY, sProxy.c_str());
} // write function //
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &sRsp); return curl;
} /**
* 使用select函数监听multi curl文件描述符的状态
* 监听成功返回0,监听失败返回-1
*/
int curl_multi_select(CURLM * curl_m)
{
int ret = ; struct timeval timeout_tv;
fd_set fd_read;
fd_set fd_write;
fd_set fd_except;
int max_fd = -; // 注意这里一定要清空fdset,curl_multi_fdset不会执行fdset的清空操作 //
FD_ZERO(&fd_read);
FD_ZERO(&fd_write);
FD_ZERO(&fd_except); // 设置select超时时间 //
timeout_tv.tv_sec = ;
timeout_tv.tv_usec = ; // 获取multi curl需要监听的文件描述符集合 fd_set //
curl_multi_fdset(curl_m, &fd_read, &fd_write, &fd_except, &max_fd); /**
* When max_fd returns with -1,
* you need to wait a while and then proceed and call curl_multi_perform anyway.
* How long to wait? I would suggest 100 milliseconds at least,
* but you may want to test it out in your own particular conditions to find a suitable value.
*/
if (- == max_fd)
{
return -;
} /**
* 执行监听,当文件描述符状态发生改变的时候返回
* 返回0,程序调用curl_multi_perform通知curl执行相应操作
* 返回-1,表示select错误
* 注意:即使select超时也需要返回0,具体可以去官网看文档说明
*/
int ret_code = ::select(max_fd + , &fd_read, &fd_write, &fd_except, &timeout_tv);
switch(ret_code)
{
case -:
/* select error */
ret = -;
break;
case :
/* select timeout */
default:
/* one or more of curl's file descriptors say there's data to read or write*/
ret = ;
break;
} return ret;
} #define MULTI_CURL_NUM 3 // 这里设置你需要访问的url //
std::string URL = "http://website.com";
// 这里设置代理ip和端口 //
std::string PROXY = "ip:port";
// 这里设置超时时间 //
unsigned int TIMEOUT = ; /* ms */ /**
* multi curl使用demo
*/
int curl_multi_demo(int num)
{
// 初始化一个multi curl 对象 //
CURLM * curl_m = curl_multi_init(); std::string RspArray[num];
CURL * CurlArray[num]; // 设置easy curl对象并添加到multi curl对象中 //
for (int idx = ; idx < num; ++idx)
{
CurlArray[idx] = NULL;
CurlArray[idx] = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);
if (CurlArray[idx] == NULL)
{
return -;
}
curl_multi_add_handle(curl_m, CurlArray[idx]);
} /*
* 调用curl_multi_perform函数执行curl请求
* url_multi_perform返回CURLM_CALL_MULTI_PERFORM时,表示需要继续调用该函数直到返回值不是CURLM_CALL_MULTI_PERFORM为止
* running_handles变量返回正在处理的easy curl数量,running_handles为0表示当前没有正在执行的curl请求
*/
int running_handles;
while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles))
{
cout << running_handles << endl;
} /**
* 为了避免循环调用curl_multi_perform产生的cpu持续占用的问题,采用select来监听文件描述符
*/
while (running_handles)
{
if (- == curl_multi_select(curl_m))
{
cerr << "select error" << endl;
break;
} else {
// select监听到事件,调用curl_multi_perform通知curl执行相应的操作 //
while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles))
{
cout << "select: " << running_handles << endl;
}
}
cout << "select: " << running_handles << endl;
} // 输出执行结果 //
int msgs_left;
CURLMsg * msg;
while((msg = curl_multi_info_read(curl_m, &msgs_left)))
{
if (CURLMSG_DONE == msg->msg)
{
int idx;
for (idx = ; idx < num; ++idx)
{
if (msg->easy_handle == CurlArray[idx]) break;
} if (idx == num)
{
cerr << "curl not found" << endl;
} else
{
cout << "curl [" << idx << "] completed with status: "
<< msg->data.result << endl;
cout << "rsp: " << RspArray[idx] << endl;
}
}
} // 这里要注意cleanup的顺序 //
for (int idx = ; idx < num; ++idx)
{
curl_multi_remove_handle(curl_m, CurlArray[idx]);
} for (int idx = ; idx < num; ++idx)
{
curl_easy_cleanup(CurlArray[idx]);
} curl_multi_cleanup(curl_m); return ;
} /**
* easy curl使用demo
*/
int curl_easy_demo(int num)
{
std::string RspArray[num]; for (int idx = ; idx < num; ++idx)
{
CURL * curl = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);
CURLcode code = curl_easy_perform(curl);
cout << "curl [" << idx << "] completed with status: "
<< code << endl;
cout << "rsp: " << RspArray[idx] << endl; // clear handle //
curl_easy_cleanup(curl);
} return ;
} #define USE_MULTI_CURL struct timeval begin_tv, end_tv; int main(int argc, char * argv[])
{
if (argc < )
{
return -;
}
int num = atoi(argv[]); // 获取开始时间 //
gettimeofday(&begin_tv, NULL);
#ifdef USE_MULTI_CURL
// 使用multi接口进行访问 //
curl_multi_demo(num);
#else
// 使用easy接口进行访问 //
curl_easy_demo(num);
#endif
// 获取结束时间 //
struct timeval end_tv;
gettimeofday(&end_tv, NULL); // 计算执行延时并输出,用于比较 //
int eclapsed = (end_tv.tv_sec - begin_tv.tv_sec) * +
(end_tv.tv_usec - begin_tv.tv_usec) / ; cout << "eclapsed time:" << eclapsed << "ms" << endl; return ;
}
转载自: http://blog.csdn.net/zxgfa/article/details/8220724
c语言libcurl库的异步用法的更多相关文章
- 转载~kxcfzyk:Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解
Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解 多线程c语言linuxsemaphore条件变量 (本文的读者定位是了解Pthread常用多线程API和Pthread互斥锁 ...
- C语言 HTTP上传文件-利用libcurl库上传文件
原文 http://justwinit.cn/post/7626/ 通常情况下,一般很少使用C语言来直接上传文件,但是遇到使用C语言编程实现文件上传时,该怎么做呢? 借助开源的libcurl库,我们 ...
- (转) c/c++调用libcurl库发送http请求的两种基本用法
libcurl主要提供了两种发送http请求的方式,分别是Easy interface方式和multi interface方式,前者是采用阻塞的方式发送单条数据,后者采用组合的方式可以一次性发送多条数 ...
- (转)libcurl库使用方法,好长,好详细。
一.ibcurl作为是一个多协议的便于客户端使用的URL传输库,基于C语言,提供C语言的API接口,支持DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP ...
- Standard C 语言标准函数库介绍
全面巩固所知所学,往精通方向迈进! Standard C 语言标准函数库速查 (Cheat Sheet) from:http://ganquan.info/standard-c/function/ C ...
- Redis学习之路(008)- Redis C语言客户端库hiredis文档翻译
Hiredis是Redis数据库一个轻量的C语言客户端库. 之所以轻量是由于它只是简单的提供了对redis操作语句支持的接口,并没有实现具体的操作语句的功能.但正是由于这种设计使我们只要熟悉了通用的r ...
- Linux之Libcurl库的介绍与应用20170509
一.LibCurl简介 LibCurl是免费的客户端URL传输库,支持FTP,FTPS, HTTP, HTTPS, SCP, SFTP, TFTP, TELNET, DICT, FILE ,LDAP等 ...
- Standard C 语言标准函数库速查(彩色的函数列表,十分清楚)
Standard C 语言标准函数库速查 (Cheat Sheet) wcstombs 函数说明 #include <stdlib.h> size_t mbstowcs(wchar_t * ...
- libcurl库(C++)快速使用
---恢复内容开始--- libcurl是一个跨平台的网络协议库,支持http, https, ftp, gopher, telnet, dict, file, 和ldap 协议.libcurl同样支 ...
随机推荐
- 《DOM Scripting》 - 阅读笔记
DOM Scripting - Web Design with JavaScript and the Document Object Model,Jeremy Keith中文名:JavaScript ...
- 1122Shell脚本之利用mysqldump备份MySQL数据库
#!/bin/bash #Mysql 自动备份 压缩并上传到 指定ftp #设想每天凌晨3点备份mysql #编辑crontab配置文件 #00 03 * * * backupmysql.sh #压缩 ...
- sp_executeSql 用法
今天遇到了一个难题 就是把 一个拼接sql语句 的返回值 赋值给一个变量 经研究 要用sp_executeSql这个存储过程 据说是从sql 2005才开始有的 代码如下: declare @str ...
- 精通Web Analytics 2.0 (7) 第五章:荣耀之钥:度量成功
精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第五章:荣耀之钥:度量成功 我们的分析师常常得不到我们应得的喜欢,尊重和资金,因为我们没有充分地衡量一个黄金概念:成果.因为我们 ...
- BZOJ 1503: [NOI2004]郁闷的出纳员
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 10526 Solved: 3685[Submit][Stat ...
- Mysql 视图 游标 触发器 存储过程 事务
Mysql 视图 触发器 存储过程 游标 游标是从数据表中提取出来的数据,以临时表的形式存放在内存中,在游标中有一个数据指针,在初始状态下指向的是首记录,利用fetch语句可以移动该指针,从而对游标中 ...
- python作用域和多继承
python作用域 python无块级作用域 看c语言代码: #include<stdio.h> int main() { > ) { ; } printf("i = %d ...
- getResourceAsStream和getResource的用法及Demo实例
用JAVA获取文件,听似简单,但对于很多像我这样的新人来说,还是掌握颇浅,用起来感觉颇深,大家最经常用的,就是用JAVA的File类,如要取得 D:/test.txt文件,就会这样用File file ...
- [Head First设计模式]生活中学设计模式——状态模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- 大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ ItemSelector重构完结版)
一,开篇分析 Hi,大家好!大熊君又和大家见面了,还记得上一篇文章吗.主要讲述了以“jQuery的方式如何开发插件”,以及过程化设计与面向对象思想设计相结合的方式是 如何设计一个插件的,两种方式各有利 ...