c/c++呼び出しlibcurlライブラリhttpリクエストを送信する2つの基本的な使い方


libcurlは主に2つの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ヘッダ、クッキー情報、送信タイムアウト時間など、今回の送信の基本パラメータを設定します.ここで、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に1つずつ追加されます.
3、curlを呼び出すmulti_performプロセスデータ転送、転送中にeasy handlerごとに設定されたコールバック関数または構成内容が呼び出され、プログラムは関数curl_を介してmulti_fdset、select()は、データ転送などの操作をいつ行うかを判断するために情報を抽出し、関数curl_multi_performの1つの入力パラメータはまだ伝送されているデータ量を格納し、この変数を読み取ることでmulti handlesが実行済みかどうかを判断することができ、伝送完了は伝送成功を代表するものではなく、1つ以上の伝送失敗がある可能性がある.
4、呼び出し関数curl_multi_info_readは、現在または以前に伝送された情報を取得し、メッセージキューが空になるまで関数を繰り返し呼び出し、各戻り情報には対応するeasl handlerの伝送状況が含まれる.
5.1つの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 
#include 
#include 
#include 

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
"); return EXIT_FAILURE; } if(!curl_multi_timeout(cm, &curl_timeo)) { fprintf(stderr, "E: curl_multi_timeout
"); 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
", 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
", 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)
", msg->msg); } } }while(still_running); // multi stack , curl_multi_cleanup multi handler curl_multi_cleanup(cm); curl_global_cleanup(); return EXIT_SUCCESS; }