zoukankan      html  css  js  c++  java
  • (转) 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. }  


    二、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 ");  
      78.         return EXIT_FAILURE;  
      79.       }  
      80.   
      81.       if(!curl_multi_timeout(cm, &curl_timeo)) {  
      82.         fprintf(stderr, "E: curl_multi_timeout ");  
      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 ",  
      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> ",  
      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) ", 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;  
  • 相关阅读:
    毕设(五)ListView
    毕设(四)ListBox
    毕设(三)NotifyIcon
    hdu 1.2.3
    ZOJ 1789 The Suspects
    ZOJ 2833 Friendship
    git
    yum wget rpm
    上传绕过
    LAMP 和 LNMP
  • 原文地址:https://www.cnblogs.com/Kobe10/p/6388738.html
Copyright © 2011-2022 走看看