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()做清理工作。

实现代码:

  1. bool send_easy_hanler(char* post_url, req_t* req)
  2. {
  3. //easy handler的句柄
  4. CURL* curl = NULL;
  5. CURLcode res = CURLE_OK;
  6. //HTTP报文头
  7. struct curl_slist* headers = NULL;
  8. char tmp_str[256] = { 0 };
  9. //构建HTTP报文头
  10. snprintf(tmp_str, sizeof(tmp_str), "User-Agent: %s", req->user_agent_);
  11. headers = curl_slist_append(headers, tmp_str);
  12. snprintf(tmp_str, sizeof(tmp_str), "Accept-Language: %s", req->language_);
  13. headers = curl_slist_append(headers, tmp_str);
  14. snprintf(tmp_str, sizeof(tmp_str), "X-FORWORDED-FOR: %s", req->ip_.c_str());
  15. headers = curl_slist_append(headers, tmp_str);
  16. /*这个函数只能用一次,如果这个函数在curl_easy_init函数调用时还没调用,
  17. 它讲由libcurl库自动调用,所以多线程下最好在主线程中调用一次该函数以防止在线程
  18. 中curl_easy_init时多次调用*/
  19. curl_global_init(CURL_GLOBAL_ALL);
  20. //初始化easy handler句柄
  21. curl = curl_easy_init();
  22. if (curl) {
  23. //设置post请求的url地址
  24. curl_easy_setopt(curl, CURLOPT_URL, post_url);
  25. //设置HTTP头
  26. curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  27. //设置发送超时时间
  28. curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);
  29. //执行单条请求
  30. res = curl_easy_perform(curl);
  31. if (res != CURLE_OK) {
  32. //curl_easy_strerror进行出错打印
  33. LOG(WARNING) << "curl_easy_perform() failed:" << curl_easy_strerror(res);
  34. }
  35. curl_slist_free_all(headers);
  36. //这个调用用来结束一个会话.与curl_easy_init配合着用
  37. curl_easy_cleanup(curl);
  38. //在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数
  39. curl_global_cleanup();
  40. }

二、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。

源码:

    1. #include <errno.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <curl/multi.h>
    5. static const char *urls[] = {
    6. "http://www.microsoft.com",
    7. "http://www.opensource.org",
    8. "http://www.google.com",
    9. "http://www.yahoo.com",
    10. "http://www.ibm.com",
    11. "http://www.mysql.com",
    12. "http://www.oracle.com",
    13. "http://www.ripe.net",
    14. };
    15. #define MAX 8 /* number of simultaneous transfers */
    16. #define CNT sizeof(urls)/sizeof(char*) /* total number of transfers to do */
    17. /*此函数读取libcurl发送数据后的返回信息,如果不设置此函数,
    18. 那么返回值将会输出到控制台,影响程序性能*/
    19. static size_t cb(char *d, size_t n, size_t l, void *p)
    20. {
    21. /* take care of the data here, ignored in this example */
    22. (void)d;
    23. (void)p;
    24. return n*l;
    25. }
    26. //设置单个easy handler的属性添加单个easy handler到multi handler中,
    27. static void init(CURLM *cm, int i)
    28. {
    29. CURL *eh = curl_easy_init();
    30. curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, cb);
    31. curl_easy_setopt(eh, CURLOPT_HEADER, 0L);
    32. curl_easy_setopt(eh, CURLOPT_URL, urls[i]);
    33. curl_easy_setopt(eh, CURLOPT_PRIVATE, urls[i]);
    34. curl_easy_setopt(eh, CURLOPT_VERBOSE, 0L);
    35. //添加easy handler 到multi handler中
    36. curl_multi_add_handle(cm, eh);
    37. }
    38. int main(void)
    39. {
    40. CURLM *cm;
    41. CURLMsg *msg;
    42. long curl_timeo;
    43. unsigned int C=0;
    44. int max_fd, msgs_left, still_running = -1;//still_running判断multi handler是否传输完毕
    45. fd_set fd_read, fd_write, fd_except;
    46. struct timeval T;
    47. curl_global_init(CURL_GLOBAL_ALL);
    48. cm = curl_multi_init();
    49. //现在multi handler的最大连接数
    50. curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)MAX);
    51. for(C = 0; C < MAX; ++C) {
    52. init(cm, C);
    53. }
    54. do{
    55. curl_multi_perform(cm, &still_running);
    56. if(still_running) {
    57. FD_ZERO(&fd_read);
    58. FD_ZERO(&fd_write);
    59. FD_ZERO(&fd_except);
    60. //获取multi curl需要监听的文件描述符集合 fd_set
    61. if(!curl_multi_fdset(cm, &fd_read, &fd_write, &fd_except, &max_fd)) {
    62. fprintf(stderr, "E: curl_multi_fdset\n");
    63. return EXIT_FAILURE;
    64. }
    65. if(!curl_multi_timeout(cm, &curl_timeo)) {
    66. fprintf(stderr, "E: curl_multi_timeout\n");
    67. return EXIT_FAILURE;
    68. }
    69. if(curl_timeo == -1)
    70. curl_timeo = 100;
    71. //如果max_fd返回-1,休眠一段时间后继续执行curl_multi_perform
    72. if(max_fd == -1) {
    73. sleep((unsigned int)curl_timeo / 1000);
    74. }
    75. else {
    76. T.tv_sec = curl_timeo/1000;
    77. T.tv_usec = (curl_timeo%1000)*1000;
    78. /* 执行监听,当文件描述符状态发生改变的时候返回
    79. * 返回0,程序调用curl_multi_perform通知curl执行相应操作
    80. * 返回-1,表示select错误
    81. */
    82. if(0 > select(max_fd+1, &fd_read, &fd_write, &fd_except, &T)) {
    83. fprintf(stderr, "E: select(%i,,,,%li): %i: %s\n",
    84. max_fd+1, curl_timeo, errno, strerror(errno));
    85. return EXIT_FAILURE;
    86. }
    87. }
    88. }
    89. while((msg = curl_multi_info_read(cm, &msgs_left))) {
    90. if(msg->msg == CURLMSG_DONE) {
    91. char *url;
    92. CURL *e = msg->easy_handle;
    93. curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url);
    94. fprintf(stderr, "R: %d - %s <%s>\n",
    95. msg->data.result, curl_easy_strerror(msg->data.result), url);
    96. /*当一个easy handler传输完成,此easy handler仍然仍然停留在multi stack中,
    97. 调用curl_multi_remove_handle将其从multi stack中移除,然后调用curl_easy_cleanup将其关闭*/
    98. curl_multi_remove_handle(cm, e);
    99. curl_easy_cleanup(e);
    100. }
    101. else {
    102. fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg);
    103. }
    104. }
    105. }while(still_running);
    106. //当multi stack中的所有传输都完成时,调用 curl_multi_cleanup关闭multi handler
    107. curl_multi_cleanup(cm);
    108. curl_global_cleanup();
    109. return EXIT_SUCCESS;
    110. }

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

  1. 安卓中使用OkHttp发送数据请求的两种方式(同、异步的GET、POST) 示例-- Android基础

    1.首先看一下最终效果的截图,看看是不是你想要的,这个年代大家都很忙,开门见山很重要! 简要说下,点击不同按钮可以实现通过不同的方式发送OkHttp请求,并返回数据,这里请求的是网页,所以返回的都是些 ...

  2. C/C++使用libcurl库发送http请求(get和post可以用于请求html信息,也可以请求xml和json等串)

    C++要实现http网络连接,需要借助第三方库,libcurl使用起来还是很方便的 环境:win32 + vs2015 如果要在Linux下使用,基本同理 1,下载编译libcurl 下载curl源码 ...

  3. .Net Core下发送WebRequest请求的两种方式

    1.使用RestSharp.NetCore 2.使用WebApi请求方式

  4. php发送http请求的两种常用方法

    第一种:使用CURL,直接上代码,开箱即用: <?php // return file_get_contents("http://thinkphp.com/index/index/cr ...

  5. 『居善地』接口测试 — 5、使用Requests库发送POST请求

    目录 1.请求正文是application/x-www-form-urlencoded 2.请求正文是raw (1)json格式文本(application/json) (2)xml格式文本(text ...

  6. PHP发送HTTP请求的几种方式

    转发:https://blog.tanteng.me/2017/07/php-curl-guzzlehttp/ 1)PHP开发中我们常用CURL 方式封装 HTTP请求,什么是CURL? CURL 是 ...

  7. php发送post请求的三种方法示例

    本文分享下php发送post请求的三种方法与示例代码,分别使用curl.file_get_content.fsocket来实现post提交数据,大家做个参考. php发送post请求的三种方法,分别使 ...

  8. C#中Post请求的两种方式发送参数链和Body的

    POST请求 有两种方式 一种是组装key=value这种参数对的方式 一种是直接把一个字符串发送过去 作为body的方式 我们在postman中可以看到 sfdsafd sdfsdfds publi ...

  9. 转载]PhpCms V9调用指定栏目子栏目文章的两种方法

    PhpCms V9调用指定栏目子栏目文章的两种方法 第一种.直接写子栏目id ,用cat in {pc:get sql="SELECT * from v9_news where status ...

随机推荐

  1. Java-Runoob:Java Scanner 类

    ylbtech-Java-Runoob:Java Scanner 类 1.返回顶部 1. Java Scanner 类 java.util.Scanner 是 Java5 的新特征,我们可以通过 Sc ...

  2. combiner中使用状态模式

    mapreduce中的combine过程 hadoop的map过程执行完成后,每一个map都可能会产生大量的本地输出,Combiner的作用就是对map端的输出先做一次合并,减少在map和reduce ...

  3. css选择器30种

    CSS 选择器是一种模式,用于选择需要添加样式的元素.平时使用最多也是最简单的就是 #id..class 和标签选择器,在 CSS 中还有很多更加强大更加灵活的选择方式,尤其是在 CSS3 中,增加了 ...

  4. Spark-1.5.2安装--Standalone和Yarn

    Spark Standalone 1.下载scala-2.10.6包解压到指定目录,添加环境变量 #SCALA VARIABLES START export SCALA_HOME=/usr/local ...

  5. 关于SQLSERVER的全文目录跟全文索引的区别

    很久没有写随笔了,本来之前想写一篇关于SQLSERVER全文索引的随笔,可惜没有时间,一直拖到现在才有时间写,不好意思让各位久等了~ 先介绍一下SQLSERVER中的存储类对象,哈哈,先介绍一下概念嘛 ...

  6. python基础知识之列表、元祖、字典、集合、字符串。

    1.可变类型之列表 列表用 [ ]来定义是可变的,可以通过索引值来去查询里面的字段可以可以追加,删除等 names='zhangyang guyun xiangpeng xuliangwei' nam ...

  7. PHP5 ini配置文件优化

    1.1使用tmpfs作为缓存加速缓存的文件目录 [root@php-node1 ~]# mount -t tmpfs tmpfs /dev/shm/ -o size=256m [root@php-no ...

  8. mysql 更改密码

    Mac 安装mysql时会生成一个默认密码: 这个可以在通知中找到,如果你需要更改密码则继续看下面, 今天给mac安装了MySQL,安装过程非常的顺利,但是在用一个可视化工具进行连接时,需要输入密码, ...

  9. JavaScript知识总结--对象的相关概念

    一.定义 无序属性的集合. 说白了就是一个容器,可以容纳[基本值.对象或者函数],这些东西都叫做属性.每个属性都有一个名字,每个名字都映射一个值(可以是基本类型的值,也可以是引用类型的值).从以上描述 ...

  10. mysql 锁 事务隔离级别

    主题 最近在看mysql相关的书籍.实验了一些内容.分享一下,主要是关于事务隔离级别(read-committed和repeatable-read)和锁相关的. 很多网上文章上都能搜索到 read-c ...