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, 1);if (uiTimeout > 0){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 = 0;struct timeval timeout_tv;fd_set  fd_read;fd_set  fd_write;fd_set  fd_except;int     max_fd = -1;// 注意这里一定要清空fdset,curl_multi_fdset不会执行fdset的清空操作  //
    FD_ZERO(&fd_read);FD_ZERO(&fd_write);FD_ZERO(&fd_except);// 设置select超时时间  //
    timeout_tv.tv_sec = 1;timeout_tv.tv_usec = 0;// 获取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 (-1 == max_fd){return -1;}/*** 执行监听,当文件描述符状态发生改变的时候返回* 返回0,程序调用curl_multi_perform通知curl执行相应操作* 返回-1,表示select错误* 注意:即使select超时也需要返回0,具体可以去官网看文档说明*/int ret_code = ::select(max_fd + 1, &fd_read, &fd_write, &fd_except, &timeout_tv);switch(ret_code){case -1:/* select error */ret = -1;break;case 0:/* select timeout */default:/* one or more of curl's file descriptors say there's data to read or write*/ret = 0;break;}return ret;
}#define MULTI_CURL_NUM 3// 这里设置你需要访问的url //
std::string     URL     = "http://website.com";
// 这里设置代理ip和端口  //
std::string     PROXY   = "ip:port";
// 这里设置超时时间  //
unsigned int    TIMEOUT = 2000; /* 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 = 0; idx < num; ++idx){CurlArray[idx] = NULL;CurlArray[idx] = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);if (CurlArray[idx] == NULL){return -1;}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 (-1 == 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 = 0; 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 = 0; idx < num; ++idx){curl_multi_remove_handle(curl_m, CurlArray[idx]);}for (int idx = 0; idx < num; ++idx){curl_easy_cleanup(CurlArray[idx]);}curl_multi_cleanup(curl_m);return 0;
}/*** easy curl使用demo*/
int curl_easy_demo(int num)
{std::string     RspArray[num];for (int idx = 0; 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 0;
}#define USE_MULTI_CURLstruct timeval begin_tv, end_tv;int main(int argc, char * argv[])
{if (argc < 2){return -1;}int num = atoi(argv[1]);// 获取开始时间 //
    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) * 1000 +(end_tv.tv_usec - begin_tv.tv_usec) / 1000;cout << "eclapsed time:" << eclapsed << "ms" << endl;return 0;
}

libcurl库的异步用法相关推荐

  1. linux libcurl 库使用方法

    一.ibcurl简介 作为是一个多协议的便于客户端使用的URL传输库,基于C语言,提供C语言的API接口,支持DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, I ...

  2. 状态模式的介绍及状态机模型的函数库javascript-state-machine的用法和源码解析

    文章大体就两部分: 状态模式 状态机模型的函数库javascript-state-machine的用法和源码解析 场景及问题背景: 我们平时开发时本质上就是对应用程序的各种状态进行切换并作出相应处理. ...

  3. Flutter开发指南之理论篇:Dart语法04(库,异步,正则表达式)

    总目录 Flutter开发指南之理论篇:Dart语法01(数据类型,变量,函数) Flutter开发指南之理论篇:Dart语法02(运算符,循环,异常) Flutter开发指南之理论篇:Dart语法0 ...

  4. linux openssl libcurl库 交叉编译

    目录 一.编译前环境准备 二.编译openssl 三.编译curl 一.编译前环境准备 使用的内核:4.15.0-118-generic(命令:uname -r可以查看) 交叉编译器:aarch64- ...

  5. 使用libcurl库编写HTTP客户端(包括GET/POST/HTTPS)

    最近在写一个应用程序, 需要与HTTP服务器进行数据交互, 于是乎自己写了一个类似wget的功能的客户端, 实现很简单, 但是功能不给力, 只可基本功能. 于是又在网上找了找, 发现使用libcurl ...

  6. Python爬虫入门(4):Urllib库的高级用法

    Python爬虫入门(1):综述 Python爬虫入门(2):爬虫基础了解 Python爬虫入门(3):Urllib库的基本使用 Python爬虫入门(4):Urllib库的高级用法 Python爬虫 ...

  7. python的numpy库的基本用法_python numpy库np.percentile用法说明

    在python中计算一个多维数组的任意百分比分位数,此处的百分位是从小到大排列,只需用np.percentile即可-- a = range(1,101) #求取a数列第90%分位的数值 np.per ...

  8. 五、Requests库详细的用法

    文章目录 Requests库介绍 Requests库安装 Requests库基本请求 get请求 post请求 自定义请求头部 设置超时时间 代理访问 重定向 ssl验证 获取响应信息 session ...

  9. 网络编程知识预备(5) ——libcurl库简介及其编程访问百度首页

    本文为学习笔记,整合课程内容以及下列文章: 其中,libcurl函数库常用字段解读部分: 参考博文:原文地址 作者:冬冬他哥哥 目录 Libcurl库简介 Libcurl等三方库的通用编译方法 三方库 ...

最新文章

  1. LeetCode:汇总区间【228】
  2. AI(artificial intelligence)的学习
  3. 内存占用少,计算速度快!华为诺亚方舟Lab开源即插即用的多用卷积核(NeurIPS 2018)...
  4. 用java swing做连连看_java基于swing实现的连连看代码
  5. 巴特沃斯滤波器 python_巴特沃斯、切比雪夫、贝塞尔滤波器的区别
  6. IT人才需要怎样的沟通表达能力
  7. 【强推】10个有趣的Python程序
  8. Fgui切割图集为散图
  9. ios 测试证书配置
  10. 华为云IoT提出万物互联新范式,从万物感知到万物生长
  11. 有关vista系统的激活工具
  12. 定常系统(时不变系统)和时变系统
  13. 【上古秘籍】之Eclipse的秘籍 转
  14. 怎么把照片转换成jpg格式?这个好方法拿去
  15. 自学计算机图形学OpenGL(五)DDA数值微分线段法
  16. Python3-基础语法
  17. Java——时间复杂度、空间复杂度详解
  18. 修复 Rancher 2.5.x 内部证书过期导致无法启动的顽疾
  19. 如何隐藏excel公式?如何取消隐藏?
  20. 高级转录组调控分析和R语言数据可视化第十四期 (线上线下开课)

热门文章

  1. mysql双向同步读写_mysql数据双向同步
  2. 项目下创建文件_Linux 下创建和使用交换文件
  3. Git的安装与使用教程
  4. 关于Mac重启之后壁纸总是恢复默认的解决办法
  5. 代码编辑器sublime text 4使用小技巧--快捷键说明
  6. oracle 天转换成月函数_oracle 日期转换格式 函数
  7. 如何实现轮播图的内容的多少随div的大小动态变化_小程序学习日志8:swiper滑动轮播组件(轮播图)(上)...
  8. 基于JavaFX的Linux进程树
  9. c++堆栈溢出怎么解决_Windows Kernel Exploit 内核漏洞学习(2)-内核栈溢出
  10. python mssql session_python的web框架webpy【session amp; cookie】五 - 莫激动 - ITeye博客