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

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

源码:

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

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

  if(!curl_multi_timeout(cm, &amp;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 &gt; select(max_fd+1, &amp;fd_read, &amp;fd_write, &amp;fd_except, &amp;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, &amp;msgs_left))) {
  if(msg-&gt;msg == CURLMSG_DONE) {
    char *url;
    CURL *e = msg-&gt;easy_handle;
    curl_easy_getinfo(msg-&gt;easy_handle, CURLINFO_PRIVATE, &amp;url);
    fprintf(stderr, "R: %d - %s &lt;%s&gt;\n",
            msg-&gt;data.result, curl_easy_strerror(msg-&gt;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-&gt;msg);
  }
}

}while(still_running);

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

return EXIT_SUCCESS;
}

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: libcurl是一个C语言,用于支持各种协议的数据传输。在编写代码时,需要先下载libcurl的开发,然后在代码中包含相应的头文件。接着,需要链接libcurl文件。 以下是在Linux操作系统下使用gcc编译调用libcurl的示例: 1. 安装libcurl开发 可以使用包管理器安装libcurl开发,例如在Ubuntu/Debian系统下执行以下命令: sudo apt-get install libcurl4-gnutls-dev 2. 编写代码 在代码中,需要包含curl/curl.h头文件,并调用libcurl提供的函数进行数据传输。例如: #include <curl/curl.h> int main(void) { CURL *curl; CURLcode res; curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://www.example.com"); res = curl_easy_perform(curl); if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); curl_easy_cleanup(curl); } return 0; } 3. 编译代码 在命令行中执行以下命令进行编译: gcc -o myprogram mycode.c -lcurl 其中,myprogram为可执行文件名,mycode.c为代码文件名。参数-lcurl指定链接libcurl。 4. 运行程序 在命令行中执行以下命令运行程序: ./myprogram 以上就是使用gcc编译调用libcurl基本步骤。在编程过程中,还需要注意设置相关选项以满足自己的需求。 ### 回答2: 在进行c编译调用libcurl前,我们需要先了解一些基础知识: 首先,libcurl是一个免费、开源的客户端 URL 传输,它支持众多协议,例如:FTP、FTPS、HTTPHTTPS、SCP、SFTP、SMTP、POP3、IMAP 等。同时,libcurl提供了易于使用的API,方便程序员在自己的应用中调用。 其次,对于c语言编译调用libcurl,我们需要下面的步骤: 1. 下载并安装curl,使用命令行方式,如Ubuntu系统可以使用以下命令进行安装: sudo apt-get install libcurl4-openssl-dev 2. 下载或拷贝需要使用libcurl的源文件,也就是c语言文件。 3. 在c语言文件中,首先添加头文件 “curl/curl.h”,然后就可以通过调用API来使用libcurl了。 4. 具体的API函数使用方式可以查阅libcurl的官方文档进行学习和理解,例如使用curl_easy_setopt函数来设置curl句柄,然后使用curl_easy_perform函数来执行请求。 5. 可以通过编译运行来验证调用libcurl是否成功,错误信息可以看编译器的输出和libcurl的API返回值。 总之,使用c语言编译调用libcurl需要先安装curl,然后在c语言文件中添加头文件和API函数调用等内容。对于API函数的使用,需要经过学习和实践来掌握和理解。 ### 回答3: libcurl是一个用于在应用程序中进行HTTP、FTP、SMTP等通信的开源Clibcurl有许多功能,包括支持多种协议、支持不同的认证方式以及支持多线程操作等。 编译调用libcurl的步骤如下: 1. 下载libcurl并解压。 2. 打开命令行终端,转到解压后的libcurl目录下。 3. 输入命令“./configure”,进行配置,生成Makefile文件。 4. 输入命令“make”,进行编译。 5. 输入命令“make install”,将编译好的文件安装到系统目录下。 6. 在程序中调用libcurl,需要包含相关的头文件,并链接对应的文件。 例如,使用gcc编译程序时,需要添加如下参数: gcc -o output main.c -lcurl 其中,main.c是程序源文件,-lcurl表示链接libcurl。 在程序中调用libcurl时,需要使用相关的API函数。例如,使用curl_easy_init()函数初始化一个curl句柄,使用curl_easy_setopt()函数设置各种参数,使用curl_easy_perform()函数执行通信操作。 总的来说,编译调用libcurl并不复杂,只需要按照以上步骤进行操作即可。使用libcurl可以大大简化网络通信操作,提高程序的可移植性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值