c/c++调用libcurl库发送http请求的两种基本用法

2023-05-16

libcurl主要提供了两种发送http请求的方式,分别是Easy interface方式和multi interface方式,前者是采用阻塞的方式发送单条数据,后者采用组合的方式可以一次性发送多条数据

一、Easy interface

libcurl的easy interface是最基本的用法,简要流程为:
1、在主线程中调用curl_global_init(CURL_GLOBAL_ALL)初始化
2、调用curl_easy_init获取一个句柄;
3、调用curl_easy_setopt函数设置此次传输的一些基本参数,如url地址、http头、cookie信息、发送超时时间等,其中,CURLOPT_URL是必设的选项;
4、设置完成后,调用curl_easy_perform函数发送数据;
5、数据发送完毕后,调用curl_easy_cleanup清空句柄;
6、调用curl_global_cleanup()做清理工作。

实现代码:

bool send_easy_hanler(char* post_url, req_t* req)
{
  //easy handler的句柄
  CURL* curl = NULL;
  CURLcode res = CURLE_OK;
  //HTTP报文头
  struct curl_slist* headers = NULL;
  char tmp_str[256] = { 0 };

  //构建HTTP报文头
  snprintf(tmp_str, sizeof(tmp_str), "User-Agent: %s", req->user_agent_);
  headers = curl_slist_append(headers, tmp_str);
  snprintf(tmp_str, sizeof(tmp_str), "Accept-Language: %s", req->language_);
  headers = curl_slist_append(headers, tmp_str);
  snprintf(tmp_str, sizeof(tmp_str), "X-FORWORDED-FOR: %s", req->ip_.c_str());
  headers = curl_slist_append(headers, tmp_str);

  /*这个函数只能用一次,如果这个函数在curl_easy_init函数调用时还没调用,
  它讲由libcurl库自动调用,所以多线程下最好在主线程中调用一次该函数以防止在线程
  中curl_easy_init时多次调用*/
  curl_global_init(CURL_GLOBAL_ALL);
  
  //初始化easy handler句柄
  curl = curl_easy_init();
  if (curl) {
	//设置post请求的url地址
    curl_easy_setopt(curl, CURLOPT_URL, post_url);
	//设置HTTP头
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
	//设置发送超时时间
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);

	//执行单条请求
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
	  //curl_easy_strerror进行出错打印
      LOG(WARNING) << "curl_easy_perform() failed:" << curl_easy_strerror(res);
    }
	
    curl_slist_free_all(headers);
	
	//这个调用用来结束一个会话.与curl_easy_init配合着用
    curl_easy_cleanup(curl);
	
	//在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数
	curl_global_cleanup();
}

二、multi interface
multi interface提供了多种easy interface没有的特性,主要是
1、提供了pull接口,使用libcurl的程序能够决定何时何处调用libcurl来get/send数据
2、在同一线程中实现多条数据同时发送,且并没有使得程序更加复杂
3、程序可以在自己的文件描述符和curl的文件描述符中同时等待执行
4、提供基于事件的处理、扩大传输规模到数千个并发连接

multi接口的使用会比easy 接口稍微复杂点,毕竟multi接口是依赖easy接口的,简要流程为:
1、使用curl_multi_init创建一个multi handle,这个handler会在后续的curl_multi_*函数中使用multi handler可以同时并发传输多条数据,每一条单独的数据是由一个easy handler创建;
2、需要事先将需要传输的所有easyhandler创建好,并使用curl_easy_setopt设置各自属性,接着调用curl_multi_add_handle函数逐个添加到multi handle中;
3、调用curl_multi_perform进程数据传输,传输过程中将会调用每一个easy handler设置的回调函数或者配置内容,程序通过函数curl_multi_fdset、select()提取信息来判断何时进行数据传输等操作,函数curl_multi_perform的一个输入参数储存仍在进行传输的数据量,通过读取该变量,可以判断multi handles是否运行完毕,传输完毕不代表传输成功,可能有一个或多个传输失败;
4、调用函数curl_multi_info_read可以获取当前或之前传输的信息,重复调用该函数直到该消息队列为空,每一条返回信息都包含对应的easl handler的传输情况;
5、当一个easy handler传输完成,此easy handler仍然仍然停留在multi stack中,需要调用curl_multi_remove_handle将其从multi stack中移除,然后调用curl_easy_cleanup将其关闭;
6、当multi stack中的所有传输都完成时,调用 curl_multi_cleanup关闭multi handler,需要注意的是事先要调用curl_easy_cleanup逐个清空所有easy handler。

源码:

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <curl/multi.h>

static const char *urls[] = {
  "http://www.microsoft.com",
  "http://www.opensource.org",
  "http://www.google.com",
  "http://www.yahoo.com",
  "http://www.ibm.com",
  "http://www.mysql.com",
  "http://www.oracle.com",
  "http://www.ripe.net",
};

#define MAX 8 /* number of simultaneous transfers */
#define CNT sizeof(urls)/sizeof(char*) /* total number of transfers to do */

/*此函数读取libcurl发送数据后的返回信息,如果不设置此函数,
那么返回值将会输出到控制台,影响程序性能*/
static size_t cb(char *d, size_t n, size_t l, void *p)
{
  /* take care of the data here, ignored in this example */
  (void)d;
  (void)p;
  return n*l;
}

//设置单个easy handler的属性添加单个easy handler到multi handler中,
static void init(CURLM *cm, int i)
{
  CURL *eh = curl_easy_init();

  curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, cb);
  curl_easy_setopt(eh, CURLOPT_HEADER, 0L);
  curl_easy_setopt(eh, CURLOPT_URL, urls[i]);
  curl_easy_setopt(eh, CURLOPT_PRIVATE, urls[i]);
  curl_easy_setopt(eh, CURLOPT_VERBOSE, 0L);

  //添加easy handler 到multi handler中
  curl_multi_add_handle(cm, eh);
}

int main(void)
{
  CURLM *cm;
  CURLMsg *msg;
  long curl_timeo;
  unsigned int C=0;
  int max_fd, msgs_left, still_running = -1;//still_running判断multi handler是否传输完毕
  fd_set fd_read, fd_write, fd_except;
  struct timeval T;

  curl_global_init(CURL_GLOBAL_ALL);

  cm = curl_multi_init();

  //现在multi handler的最大连接数
  curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)MAX);

  for(C = 0; C < MAX; ++C) {
    init(cm, C);
  }

  
  do{
    curl_multi_perform(cm, &still_running);

    if(still_running) {
      FD_ZERO(&fd_read);
      FD_ZERO(&fd_write);
      FD_ZERO(&fd_except);

	  //获取multi curl需要监听的文件描述符集合 fd_set
      if(!curl_multi_fdset(cm, &fd_read, &fd_write, &fd_except, &max_fd)) {
        fprintf(stderr, "E: curl_multi_fdset\n");
        return EXIT_FAILURE;
      }

      if(!curl_multi_timeout(cm, &curl_timeo)) {
        fprintf(stderr, "E: curl_multi_timeout\n");
        return EXIT_FAILURE;
      }
      if(curl_timeo == -1)
        curl_timeo = 100;

	  //如果max_fd返回-1,休眠一段时间后继续执行curl_multi_perform
      if(max_fd == -1) {
        sleep((unsigned int)curl_timeo / 1000);
      }
      else {
        T.tv_sec = curl_timeo/1000;
        T.tv_usec = (curl_timeo%1000)*1000;

		/* 执行监听,当文件描述符状态发生改变的时候返回
         * 返回0,程序调用curl_multi_perform通知curl执行相应操作
         * 返回-1,表示select错误
		 */
        if(0 > select(max_fd+1, &fd_read, &fd_write, &fd_except, &T)) {
          fprintf(stderr, "E: select(%i,,,,%li): %i: %s\n",
              max_fd+1, curl_timeo, errno, strerror(errno));
          return EXIT_FAILURE;
        }
      }
    }

    while((msg = curl_multi_info_read(cm, &msgs_left))) {
      if(msg->msg == CURLMSG_DONE) {
        char *url;
        CURL *e = msg->easy_handle;
        curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url);
        fprintf(stderr, "R: %d - %s <%s>\n",
                msg->data.result, curl_easy_strerror(msg->data.result), url);
		/*当一个easy handler传输完成,此easy handler仍然仍然停留在multi stack中,
		调用curl_multi_remove_handle将其从multi stack中移除,然后调用curl_easy_cleanup将其关闭*/
        curl_multi_remove_handle(cm, e);
        curl_easy_cleanup(e);
      }
      else {
        fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg);
      }
    }
  }while(still_running);

  //当multi stack中的所有传输都完成时,调用 curl_multi_cleanup关闭multi handler
  curl_multi_cleanup(cm);
  curl_global_cleanup();

  return EXIT_SUCCESS;
}

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

c/c++调用libcurl库发送http请求的两种基本用法 的相关文章

  • OPENCV检测矩形并计算其中心

    include 34 cv h 34 include 34 highgui h 34 include lt stdio h gt include lt math h gt include lt string h gt pragma comm
  • Jetson Xavier NX/AGX快速安装Intel Realsense SDK并使用D455

    Jetson Xavier NX AGX快速安装Intel Realsense SDK并使用D455 环境搭建及测试 1 安装脚本下载 xff1a github链接 xff1a https github com jetsonhacks in
  • AirSim无人机键盘控制

    AirSim仿真中实现多键盘按键控制 前言本文实现效果一 环境依赖二 多按键检测1 Pygame中的常用的键盘鼠标事件2 利用Pygame实现的多按键检测 AirSim中键盘控制实现下期预告 前言 有时候为了方便在AirSim调试无人机 x
  • 使用多电脑进行AirSim联合仿真

    文章目录 前言一 什么时候适合用两台电脑进行仿真 xff1f 二 怎么使用多电脑联合仿真 局域网内 1 获取UE4渲染端的IP地址2 修改程序接口 前言 随着仿真无人机数量的增加 xff0c 单台电脑越来越难以做到实时渲染 xff0c 这时
  • H.265编码原理入门

    视频编码的目的是为了压缩原始视频 xff0c 压缩的主要思路是从空间 时间 编码 视觉等几个主要角度去除冗余信息 由于 H 264 出色的数据压缩比率和视频质量 xff0c 成为当前市场上最为流行的编解码标准 而 H 265 是在 H 26
  • Go语言 GMP面试题(GMP调度示例)

    GMP面试题 第一段第二段 第一段 span class token keyword package span main span class token keyword import span span class token strin
  • 卡尔曼滤波里观测值凭什么用观测方程来表示?

    观测方程Z k 61 H X k 43 V k 为什么是由状态值和误差决定的 xff1f 不应该是由传感器输进去的吗 为啥只赋了一个初值 xff0c 就不再输入了 xff1f 在师兄解释下 xff0c 我终于明白了 因为这是仿真 xff01
  • Linux 内核的面向对象设计思想

    使用C语言实现面向对象设计的方法 Linux内核用C语言实现了面向对象的设计思想 即使用了三方面的特性 xff1a 封装 继承 多态 使用结构体实现了对对象的封装 xff1b 某一结构体成员中含有其他结构体的实例 xff0c 实现了一个结构
  • Win11安装OBS Studio的详细步骤图文教程

    Win11安装OBS Studio的详细步骤图文教程分享 一些用户为了进行更方便的视频直播录制功能 xff0c 需要在电脑上安装OBS Studio 但是自己对这款软件比较陌生 xff0c 而且因为它是英文的 xff0c 不知道怎么安装 接
  • Win11系统怎么安装到虚拟机的方法分享

    Win11系统怎么安装到虚拟机的方法分享 有的用户想要在自己的虚拟机里面去安装Win11系统来进行使用 这样就可以在虚拟机里面去测试系统了 xff0c 系统有一些问题也可以不用担心 那么怎么在虚拟机里面去安装Win11系统呢 xff1f 接
  • 上传文件超过限制,造成长时间无响应的解决方案

    在上传大文件 xff0c 造成长时间没有响应的情况的解决方案 xff1a 上传大文件时 xff0c 因为http协议的响应问题 xff0c 造成长时间不能向客户端发送响应请求头 解决方案 xff1a 1 向服务器发送上传大文件的reques
  • checkbox的jsTree的一个调用

    lt DOCTYPE HTML PUBLIC 34 W3C DTD HTML 4 01 Transitional EN 34 gt lt html gt lt head gt lt meta http equiv 61 34 Content
  • 灵活使用递归算法,生成Excel文件中的复合表头

    最近 xff0c 在开发中 xff0c 需要导出数据到excel文件 xff0c 文件的表头的格式是不一致的 有复合表头 xff0c 也有单表头 xff0c 那么如何灵活地生成excel文件中的复合表头 首先有一个JSON字符串格式的字段描
  • 在 ibm http server 和 websphere 之间配置 ssl

    在WebSphere的环境中 xff0c 配置SSL xff0c 有一些细节需要注意 xff1a 1 最好是先安装 ibm http server7 32bit xff0c websphere7 再安装插件 2 http server 需要
  • Ext4使用总结(二)简单的hbox布局

    布局的合理利用 xff1a 如图 xff1a xtype 39 container 39 margins 39 5 0 0 0 39 layout align 39 stretch 39 type 39 hbox 39
  • 凤凰涅槃-在2016年的我

    2016年已经过去 xff0c 在过去的一年 xff0c 有许多的收获 xff0c 也有许多的不足 xff0c 过去的2016年 xff0c 我想到的一个词语来概括2016 xff0c 就是 34 凤凰涅槃 34 凤凰涅槃 xff1a 凤凰
  • 图床个人使用

    在这里插入图片描述
  • 软件开发者的精力管理(一)

    精力管理对于软件开发者来讲是非常重要的 不希望自己被长周期的项目拖垮 xff0c 不希望被连续的加班所累 我个人认为泛义的时间管理是涉及到多个方面的 而心理学 精力管理则是非常重要的 作为一名从事了多年软件开发的从业者 xff0c 我的一个
  • 如何高效能地学习和使用"工具"?

    在软件开发中 xff0c 应该注意工具的合理使用 xff0c 使得自己变得高效起来 1 工具也是产品 xff0c 有许多的工具是产品化的 既然是产品 xff0c 就很多的服务 xff0c 例如帮助文档 xff0c 论坛 xff0c 咨询人员
  • Ext4使用总结(十二) 采用 CellEditing 方式的Grid,如何取得修改的单元格数据值

    使用cellediting方式编辑数据的grid在保存数据时 xff0c 需要进行数据的处理 xff0c 所以数据处理的方式需要特别注意 cellEditing 插件的事件 listeners edit function editor e

随机推荐

  • 树莓派——开机指南

    1 准备 硬件准备 树莓派一块 SD卡 xff08 小卡 xff09 读卡器 树莓派电源或安卓手机电源 xff08 功率10w以上 xff0c 不然会导致电压不足会影响其性能 xff09 一台电脑 xff08 可以没有显示屏和鼠标键盘 xf
  • cmakelist.txt编写总结

    简述 前期进行autoware auto中泊车代码移植 xff0c 考虑到auto基于ros2编写 xff0c 而代码使用环境为ros1 xff0c 需要进行cmakelist的重写 xff1a 难点为ros2编译指令向ros1迁移 xff
  • [解题报告] CSDN竞赛第15期

    CSDN编程竞赛报名地址 xff1a https edu csdn net contest detail 29 1 求并集 题目 由小到大输出两个单向有序链表的并集 如链表 A 1 gt 2 gt 5 gt 7 链表 B 3 gt 5 gt
  • [解题报告] CSDN竞赛第17期

    CSDN编程竞赛报名地址 xff1a https edu csdn net contest detail 31 1 判断胜负 题目 已知两个字符串A B 连续进行读入n次 每次读入的字符串都为A B 输出读入次数最多的字符串 解题报告 模拟
  • [解题报告] CSDN竞赛第18期

    CSDN编程竞赛报名地址 xff1a https edu csdn net contest detail 32 1 单链表排序 题目 单链表的节点定义如下 xff08 C 43 43 xff09 xff1a class Node publi
  • [解题报告] CSDN竞赛第22期

    CSDN编程竞赛报名地址 xff1a https edu csdn net contest detail 36 1 c 43 43 难题 大数加法 题目 大数一直是一个c语言的一个难题 现在我们需要你手动模拟出大数加法过程 请你给出两个大整
  • [解题报告] CSDN竞赛第23期

    CSDN编程竞赛报名地址 xff1a https edu csdn net contest detail 37 1 排查网络故障 题目 A地跟B地的网络中间有n个节点 xff08 不包括A地和B地 xff09 xff0c 相邻的两个节点是通
  • Python3中的configparser模块

    configparser模块简介 该模块适用于配置文件的格式与windows ini文件类似 xff0c 可以包含一个或多个节 xff08 section xff09 xff0c 每个节可以有多个参数 xff08 键 61 值 xff09
  • CSDN竞赛第24期

    CSDN编程竞赛报名地址 xff1a https edu csdn net contest detail 38 这次写完第一道题时遇到一个奇怪的情况 xff1a 一直在 运行中 xff0c 然后发现每道题输入做任意代码都出现一直运行中 跟小
  • [Python开发] 使用python读取图片的EXIF

    使用python读取图片的EXIF 方法 使用PIL Image读取图片的EXIF 使用https pypi python org pypi ExifRead 读取图片的EXIF xff0c 得到EXIF标签 xff08 dict类型 xf
  • Partial Least Squares Regression 偏最小二乘法回归

    介绍 定义 偏最小二乘回归 多元线性回归分析 43 典型相关分析 43 主成分分析 输入 xff1a n m 的预测矩阵 X n p 的响应矩阵 Y 输出 X 和 Y 的投影 分数 矩阵 T U R n l 目标 xff1a 最大化 cor
  • 唐诗生成器

    使用唐诗语料库 xff0c 经过去噪预处理 分词 生成搭配 生成主题等过程 xff0c 生成唐诗 csdn下载地址 xff1a http download csdn net detail lijiancheng0614 9840952 gi
  • 使用TensorFlow-Slim进行图像分类

    参考 https github com tensorflow models tree master slim 使用TensorFlow Slim进行图像分类 准备 安装TensorFlow 参考 https www tensorflow o
  • 使用TensorFlow Object Detection API进行图像物体检测

    参考 https github com tensorflow models tree master object detection 使用TensorFlow Object Detection API进行图像物体检测 准备 安装Tensor
  • 双网卡下使用udp带来的问题

    今天在工程人员现场布置程序时 xff0c 出了一个疑难问题 xff0c 客户端发送的UDP包服务程序能收到 xff0c 但是服务程序收到的包的ip地址很随机 xff0c 造成在生成唯一ID的时候出现问题 xff0c 经过仔细排查 xff0c
  • 帧融合的功能(慢镜头的制作)

    转自 xff1a http mc2109 blog 163 com blog static 253694620087217213706 帧融合的功能 xff08 慢镜头的制作 xff09 2008 08 21 19 02 13 分类 xff
  • 无人驾驶二 卡尔曼滤波与PID控制

    链接 xff1a https pan baidu com s 108cN2yyKOiouiABXTYtGOw pwd 61 1234 提取码 xff1a 1234 卡尔曼滤波形象的描述见 xff1a 卡尔曼滤波原理及实现 曦爷的博客 CSD
  • JetsonTX2和TX2I的镜像备份与恢复及内核、DTB更新

    为了HDMI转CSI的图像采集模块能被识别 xff0c 可以成功采集HDMI视频图像 xff0c 最近在研究JetsonTX2和TX2I的刷机 镜像备份与恢复 xff0c 以及内核和DTB的刷入 按照https elinux org Jet
  • Dockerfile详解超全

    Dockerfile详解 环境介绍指令介绍FROMMAINTAINERLABELADDCOPYEXPOSEENV在Dockerfile中使用变量的方式 RUNCMDRUN amp amp CMDENTRYPOINTVOLUMEUSERWOR
  • c/c++调用libcurl库发送http请求的两种基本用法

    libcurl主要提供了两种发送http请求的方式 xff0c 分别是Easy interface方式和multi interface方式 xff0c 前者是采用阻塞的方式发送单条数据 xff0c 后者采用组合的方式可以一次性发送多条数据