libcurl库的异步用法

2023-05-16

 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_CURL

struct 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;
}  
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

libcurl库的异步用法 的相关文章

  • socket实现UDP通信

    UDP与TCP不同 xff0c 是一种无连接的通信方式 xff0c 相比TCP而言更加灵活 利用socket实现UDP的方式相比TCP而言也更加简单 发送方 xff1a 1 初始化套接字 2 创建socket 3 利用sendto发送数据
  • C语言之#define用法入门详解

    一 define的基本语法 在C语言中 xff0c 常量是使用频率很高的一个量 常量是指在程序运行过程中 xff0c 其值不能被改变的量 常量常使用 define来定义 使用 define定义的常量也称为符号常量 xff0c 可以提高程序的
  • 棋盘格自动生成器——四种格式(格雷码棋盘格、圆点、二维码棋盘格)

    棋盘格生成器可以生成上面四种格式的标定板 想要多大想要几行几列都可以动态设置 非常好用 对于自己写代码或用cad画都比较浪费时间 这个生成器可以立刻生成pdf 只要打印机不设置缩放 即可正常尺寸打印 非常非常好用 介绍给大家这个好用的地址
  • python爬虫-验证码的处理

    在爬取网页数据时 xff0c 经常出现需要登录账户且要输入验证码的情况 以http www santostang com wp login php action 61 register该网页为例 xff0c 需要先使用浏览器的检查功能找到f
  • HTTP协议的解码和编码

    HTTP协议的解码和编码 编码规范URL的编码与解码 编码 规范实战 xff1a 使用fiddler来抓住http请求 相当于各省各地的人说不同的话 xff0c 大家互相听不懂 xff0c 那么http就相当于有一个翻译器 xff0c 能够
  • Linux服务器上请求接口说明

    Linux服务器上请求接口说明 一 参数指令说明 X 指定请求方法 x 指定HTTP请求的代理 H 指定请求标头 d 发送POST请求提交的数据 xff0c 使用 d参数后 xff0c 会自动将请求转为POST xff0c HTTP请求会自
  • 编写一个程序,将两个字符串连接起来,不要用stracat 函数

    可能写的不好 xff0c 希望对你们有帮助 include lt stdio h gt int main int a 61 0 b 61 0 c 61 0 m 61 0 i j char str1 80 str2 80 printf 请输入
  • Linux ulimit命令详解

    ulimit 是一个计算机命令 xff0c 用于shell启动进程所占用的资源 xff0c 可用于修改系统资源限制 命令常用参数 H 设置硬资源限制 S 设置软资源限制 a 显示当前所有的资源限制 c size 设置core文件的最大值 单
  • 几种CAN应用层协议介绍

    一 CanOpen n CAL 提供了所有的网络管理服务和报文传送协议 xff0c 但并 没有定义 CMS 对象的内容或者正在通讯的对象的类 型 而这正是 CANopen 切入点 n CANopen 是在 CAL 基础上开发的 xff0c
  • CImage类

    我们知道 xff0c Visual C 43 43 中的CBitmap类的功能简直太弱小了 xff0c 这曾经让Visual C 43 43 在图像处理方面的功能比较尴尬 之前笔记里面 xff0c 我们采用的CBitmap配合GDI进行透明
  • PTA 7-20 表达式转换 (25分)

    算术表达式有前缀表示法 中缀表示法和后缀表示法等形式 日常使用的算术表达式是采用中缀表示法 xff0c 即二元运算符位于两个运算数中间 请设计程序将中缀表达式转换为后缀表达式 输入格式 输入在一行中给出不含空格的中缀表达式 xff0c 可包
  • Template Mode(模板方法)

    结构化程序 程序库开发人员 class Library public void step1 void step3 void step5 应用程序开发人员 class Application piblic bool Step2 bool St
  • Strategy 模式

    enum TaxBase CN Tax US Tax DE Tax class SaleOrder TaxBase tax public if tax 61 61 CN Tax else if tax 61 61 US Tax else i
  • 观察者模式

    在软件的构建过程中 xff0c 我们需要为某些对象建立一种通知依赖关系 一个对象 xff08 目标对象 xff09 发生改变 所有的依赖对象 xff08 观察者对象 xff09 都将得到通知 xff0c 如果依赖关系过于紧密 xff0c 将
  • matlab数据分类 画直方图

    我是刚刚接触matlab的小白 xff0c 在度娘和广大网友的帮助下终于完成了这个小任务 所以想记录下 xff0c 也希望可以帮助那些学习matlab的人 小任务 xff1a 主要对txt文本里的数据 进行处理下 xff0c 然后通过mat
  • 树莓派跑一个简单c++小程序教程

    我用的是树莓派3代b型 xff0c 所使用的是Debian系统的衍生系统raspbian 对系统不太了解不清楚 树莓派开发c 43 43 程序需要的工具有编辑器vim 调试器gdb 编译器gcc或者g 43 43 xff08 大神飘过就行
  • typedef 函数指针用法

    进入正文 xff1a 代码简化 促进跨平台开发的目的 typedef 行为有点像 define 宏 xff0c 用其实际类型替代同义字 不同点 xff1a typedef 在编译时被解释 xff0c 因此让编译器来应付超越预处理器能力的文本
  • 关于红外相机热成像相机的一些sdk使用方法

    将红外热成像相机转化成c格式 xff0c 从而用opencv进行显示 先看一些开发手册的函数 定义一个函数指针 typedef long CBF IR long lData long lParam CBF IR pCBFframe 相机接口
  • opencv显示图像并转换成灰度图(c++) day1

    include lt opencv2 opencv hpp gt include lt iostream gt using namespace cv int main Mat src 61 imread 34 aa jpg 34 Mat g
  • 古典问题(兔子生崽):有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少对

    基础不夯实 xff0c 工作两行泪 include lt stdio h gt int main 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 1 2 3 5 8 13 21 34 int m 61

随机推荐

  • 如果你还在用STM32F103,那么你OUT了

    自从ARM公司2007年首推出Cortex内核 xff0c ST凭借基于ARM CORTEX M3内核的STM32F1 xff0c 无疑成为了最大的赢家之一 特别是STM32F103系列 xff0c 更是成为市场上最通用的MCU系列之一 不
  • 瑞芯微RK1808开发板之进入系统

    参照RK1808 EVB用户指南 V10 20181226 pdf用户指南配置 文档获取地址https github com rockchip linux docs tree master SoC 20platform 20related
  • 瑞芯微RK1808编译rknn_demo

    操作步骤在ubuntu16 04下编译 官方给的sdk里的rknn demo不能直接编译 缺少一些动态链接库 xff0c 还需要完善一些CMakeLists txt内容 首先在rknn demo下新建一个build 进入 build文件夹下
  • libcurl在嵌入式设备C 的使用

    libcurl在嵌入式设备C 的使用 bingqingsuimeng的专栏 CSDN博客 linux configure prefix 61 root work code curl 7 61 1 curl linux disable sha
  • 某些项目因位于工作空间目录中而被隐藏

    今天晚上突然想建一个小项目 xff0c 建在了F project projectname 建完后发现项目并没有导入到Eclipse中 xff0c 于是又自己重新导入 xff0c 导入到最后一步就报了如题错误 在网上找了下原因 按照这篇博客h
  • C++关于文件检索的源码转译技巧(R"()"方式)

    在C C 43 43 编写代码的过程中 xff0c 经常会用到检索文件路径的时候 xff0c 首先要明确一点 xff0c 由于 符号是C C 43 43 的保留符号 xff0c 因此直接粘贴路径字符串在代码中是不能使用的 例如下面的方法 x
  • 嵌入式课程 之 中断和串口通信实验

    版权归如下公司 xff0c 禁止非授权转载 xff1a 北京西普阳光教育科技股份有限公司 xff08 https www simpleware com cn xff09 维周机器人科技有限公司 xff08 http www vejoe co
  • Linux系统tcp连接设置

    目录 net ipv4 tcp syn retriesnet ipv4 ip local port rangenet core somaxconnnet ipv4 tcp max syn backlognet core netdev max
  • 一种简单有效的锂电池充电均衡电路

    一种简单有效的锂电池充电均衡电路 这个均衡电路用的是三个一模一样的并联稳压电路组成的 xff0c 每个电池上并一个 电路原理图如下 xff1a 每个稳压电源都调节到4 2V 均衡的原理是 xff0c 当电池电压都小于4 2V时 xff0c
  • 【嵌入式开发工具】Makefile和Cmake

    工具配置 首先 xff0c 方便代码编辑 xff0c 安装sublime和vim xff0c 其中安装sublime过程见下 https blog csdn net yunna520 article details 114021153 注意
  • Arduino Uno PWM和IRremote库冲突问题

    问题发生环境 xff1a Arduino UNO R3控制板 xff0c 用两个L298N驱动板驱动4轮小车 xff0c 然后通过控制4路PWM来控制4个轮子的速度 xff0c 遥控方式为红外遥控 xff0c 使用的红外库是IRremote
  • [ERROR] 两个jar包中存在Qualified Name完全相同的引用冲突问题 解决方案

    分析 最近在搞Jedis xff0c 在引入jedis 2 9 0 jar和commons pool2 2 4 2 jar后初始化JedisPoolConfig时 xff0c 发现很多属性无法设置 xff08 如最大空闲连接等 xff09
  • 如何使用Visual studio C++(VC++)编译C?图解,详!!!

    如何使用Visual studio C 43 43 xff08 VC 43 43 xff09 编译C xff1f 图解 xff0c 详 xff01 xff01 xff01 之前在网上找过关于这方面的东西 xff0c 但是一直都没有看到有详细
  • 头文件与类的声明

    我们在开始学习C 43 43 时 xff0c 就应该养成规范大气的编程习惯 xff0c 头文件 header 的布局就是其中很重要的一个点 我们需要知道头文件中的防卫式声明 ifndef COMPLEX define COMPLEX 前置声
  • ubuntu C++ 和windows C# socket TCP通信

    TCP客户端代码 windows C https www cnblogs com sunev archive 2012 08 05 2604189 html using System using System Net using Syste
  • 多进程和多线程的优缺点

    在Linux下编程多用多进程编程少用多线程编程 IBM有个家伙做了个测试 xff0c 发现切换线程context的时候 xff0c windows比linux快一倍多 进出最快的锁 xff08 windows2k的 critical sec
  • 【C语言】链表及单链表基本操作

    1 什么是链表 xff1f 链表的分类 xff1f 链表是一种物理存储结构上非连续 非顺序的存储结构 xff0c 数据元素的逻辑顺序是通过链表中的指针链接次序实现的 数据结构中 xff1a 2 链表的分类 共有8种链表结构 3 单链表的基本
  • 14串聚合物锂电池保护板和电路图(带均衡功能)

    转载自 xff1a http bbs mydigit cn read php tid 61 746827 之前发过14串三元锂组装的帖子 xff0c 有坛友对保护板感兴趣 xff0c 还有的说串联充电 xff0c 早死早超生 xff0c 哈
  • HTTP的长连接和短连接

    一 什么是长连接 HTTP1 1规定了默认保持长连接 xff08 HTTP persistent connection xff0c 也有翻译为持久连接 xff09 xff0c 数据传输完成了保持TCP连接不断开 xff08 不发RST包 不
  • libcurl库的异步用法

    multi接口的使用会比easy 接口稍微复杂点 xff0c 毕竟multi接口是依赖easy接口的 xff0c 首先粗略的讲下其使用流程 xff1a curl multi init初始化一个multi curl对象 xff0c 为了同时进