0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

libcurlの使い方(easyインターフェース)

Last updated at Posted at 2025-01-12

libcurlは、curlコマンドのようなHTTP等の通信をC/C++のプログラムから実行できるライブラリである。curlコマンドと同様に、HTTPやHTTPS以外にもFTP、FTPS、SFTP、SCPなど様々なプロトコルに対応している1
libcurlを使用したプログラムをコンパイル・リンクする場合、gcc、g++やclang、clang++ではオプションで-lcurlをつける。
libcurlにはeasyインターフェース2とmultiインターフェース3の2つがあるが、この記事ではeasyインターフェースについて説明していく。

1 使用する関数

easyインターフェースで使う関数は主に5つ。

1.1 curl_easy_init

4
通信に使うハンドルを初期化し、取得する。

1.2 curl_easy_setopt

5
ハンドルにオプションを設定する。通信先のURLも含め、ほとんどの設定はここで設定することになる。
たとえば、受け取ったデータを他で使いたい場合、CURLOPT_WRITEFUNCTIONでコールバック関数を設定する必要がある。

1.3 curl_easy_perform

6
通信を実行する。通信が終了するまで後続の処理はブロックされる。
戻り値としてCURLcodeを返すので、これを使って通信が成功したかどうかを判定する。

1.4 curl_easy_getinfo

7
実行した通信に関する情報を取得する。

1.5 curl_easy_cleanup

8
ハンドルを終了する。

2 例

easyインターフェースで通信する例は以下のようになる。

sample.cpp
#include <iostream>
#include <string>
extern "C"{
#include <curl/curl.h>
}

size_t WriteCallback(char* ptr, size_t size, size_t nmemb, std::string *responseData) {
    size_t totalSize = size * nmemb;
    responseData->append(ptr, totalSize);
    return totalSize;
}

int main(int argc, char* argv[]) {
    CURL* hnd;
    CURLcode res;
    std::string responseData;

    hnd = curl_easy_init();
    if(hnd) {
        curl_easy_setopt(hnd, CURLOPT_URL, "https://example.com");
        curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &responseData);

        curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
        curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
        curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
        curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
        curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
        curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.88.1");

        res = curl_easy_perform(hnd);

        if (res != CURLE_OK) {
            std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
        } else {
            std::cout << "Response data: " << responseData << std::endl;
        }

        curl_easy_cleanup(hnd);
    }
    return 0;
}

2.1 コールバック関数

コールバック関数(上の例だとWriteCallback)はcurl_easy_setoptを使ってCURLOPT_WRITEFUNCTION9に設定する。コールバック関数の第一引数には受け取ったデータのポインタが渡される。第二引数と第三引数を掛け算すると受け取ったデータのサイズになる。
第四引数はcurl_easy_setoptCURLOPT_WRITEDATA10に指定したポインタが渡される。
コールバック関数は一回の通信でも複数回呼び出されることがあるので、一回しか呼び出されないと勘違いしてはいけない(上の例だとappend()で毎回responseDataに追記している)

2.2 設定するオプション

curl_easy_setoptで設定するオプションについては、curlコマンドで--libcurlオプションを使うのが簡単。

$ curl -s --libcurl example.c https://example.com

上のコマンドを実行すると、以下のような内容でexample.cが作成される。

example.c
/********* Sample code generated by the curl command line tool **********
 * All curl_easy_setopt() options are documented at:
 * https://curl.se/libcurl/c/curl_easy_setopt.html
 ************************************************************************/
#include <curl/curl.h>

int main(int argc, char *argv[])
{
  CURLcode ret;
  CURL *hnd;

  hnd = curl_easy_init();
  curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
  curl_easy_setopt(hnd, CURLOPT_URL, "https://example.coc");
  curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
  curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.88.1");
  curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
  curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
  curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);

  /* Here is a list of options the curl code used that cannot get generated
     as source easily. You may choose to either not use them or implement
     them yourself.

  CURLOPT_WRITEDATA was set to an object pointer
  CURLOPT_INTERLEAVEDATA was set to an object pointer
  CURLOPT_WRITEFUNCTION was set to a function pointer
  CURLOPT_READDATA was set to an object pointer
  CURLOPT_READFUNCTION was set to a function pointer
  CURLOPT_SEEKDATA was set to an object pointer
  CURLOPT_SEEKFUNCTION was set to a function pointer
  CURLOPT_ERRORBUFFER was set to an object pointer
  CURLOPT_STDERR was set to an object pointer
  CURLOPT_HEADERFUNCTION was set to a function pointer
  CURLOPT_HEADERDATA was set to an object pointer

  */

  ret = curl_easy_perform(hnd);

  curl_easy_cleanup(hnd);
  hnd = NULL;

  return (int)ret;
}
/**** End of sample code ****/

このように、コールバック以外のオプションについては自動で生成してくれるので、そのまま使えば良い。

3 通信を複数回行う場合

通信を複数回行う場合、一度使用したハンドルを使いまわすほうがリソース的には効率的になる。
curl_easy_setoptで設定したオプションをデフォルトに戻したい場合はcurl_easy_reset11を使用する。

4 マルチスレッド

12
マルチスレッド環境では、スレッド同士でハンドルを共有してはいけない。各スレッドで別々にスレッドを取得する。
libcurlをマルチスレッドで使用する場合、以前はcurl-global-initをプログラム開始時に明示的に呼ぶ必要があった(例:13)が、libcurl 7.84.0以降では多くの環境でcurl-global-initはスレッドセーフになっているよう(もちろん明示的に呼んでも問題ない)。
マルチスレッド環境の場合、curl_easy_setoptCURLOPT_NOSIGNAL14を1Lに設定する必要がある。

参考リンク

https://curl.se/libcurl/
https://curl.se/libcurl/c/libcurl-tutorial.html
https://everything.curl.dev/libcurl/index.html

  1. https://curl.se/libcurl/

  2. https://curl.se/libcurl/c/libcurl-easy.html

  3. https://curl.se/libcurl/c/libcurl-multi.html

  4. https://curl.se/libcurl/c/curl_easy_init.html

  5. https://curl.se/libcurl/c/curl_easy_setopt.html

  6. https://curl.se/libcurl/c/curl_easy_perform.html

  7. https://curl.se/libcurl/c/curl_easy_getinfo.html

  8. https://curl.se/libcurl/c/curl_easy_cleanup.html

  9. https://curl.se/libcurl/c/CURLOPT_WRITEFUNCTION.html

  10. https://curl.se/libcurl/c/CURLOPT_WRITEDATA.html

  11. https://curl.se/libcurl/c/curl_easy_reset.html

  12. https://curl.se/libcurl/c/threadsafe.html

  13. https://blog.regrex.jp/2019/07/01/%E3%83%9E%E3%83%AB%E3%83%81%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%E3%81%A7%E3%80%8Clibcurl%E3%80%8D%E4%BD%BF%E7%94%A8%E6%99%82%E3%81%AE%E6%B3%A8%E6%84%8F%E7%82%B9/

  14. https://curl.se/libcurl/c/CURLOPT_NOSIGNAL.html

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?