現在、Web API を使用してアプリケーション間でデータを交換するのが一般的です。 JavaScript、Python、PHP などの言語で API を使用するためのチュートリアルはたくさんありますが、システム レベルのプログラミングに関連付けられることが多い C がこの目的で考慮されることはほとんどありません。ただし、C は API リクエストを完全に処理できるため、効率性と低レベルの制御のために C がすでに使用されている、販売時点情報管理 (PoS) システム、IoT デバイス、組み込みアプリケーションなどのシナリオでは実行可能な選択肢となります。
この記事では、libcurl ライブラリを利用して C で API を使用する方法について説明します。最後には、C を使用して API からデータをフェッチして処理する方法と、このアプローチが最新の開発にも関連する理由を理解できるようになります。
API の使用に C を使用する理由は何ですか?
Web 開発では高級言語が主流ですが、特定のユースケースで API を使用するには C が依然として実用的な選択肢です。
- パフォーマンス: C は、高いパフォーマンスと最小限のオーバーヘッドを提供し、IoT デバイスなどのリソースに制約のある環境に適しています。
- 制御: 直接メモリ管理により、特に組み込みシステムの場合、微調整された最適化が可能になります。
- 相互運用性: C が広く使用されているということは、C がハードウェア、センサー、その他の周辺機器の制御などのシステムレベルの操作とうまく統合されていることを意味します。
- 寿命: C で構築されたアプリケーションは、特に小売業や製造業などの業界では、寿命が長いことがよくあります。
libcurl の紹介: C での HTTP 用ツール
C で API を使用するには、libcurl が頼りになるライブラリです。これは、HTTP、HTTPS、FTP などを介したネットワーク リクエストを処理するための、オープンソースでポータブルな機能豊富なライブラリです。以下をサポートします:
- GET、POST、その他の HTTP リクエストを実行します。
- ヘッダーと認証の処理。
- 応答を効率的に処理します。
C で API を使用するための基本的な手順
JSON データをフェッチする実際の例に焦点を当てて、C を使用して API を使用するプロセスを見てみましょう。
セットアップとインストール
libcurl を使用するには、システムにインストールする必要があります。ほとんどの Linux ディストリビューションでは、これは次のように実行できます。
sudo apt-get install libcurl4-openssl-dev
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
Windows では、libcurl Web サイトからプリコンパイルされたバイナリをダウンロードできます: https://curl.se/download.html
macOS で Homebrew を使用している場合は、
経由でインストールできます。
brew install curl
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
C プログラムの構造化
API からデータをフェッチする単純な C プログラムには、次のコンポーネントが含まれます。
- libcurl を初期化しています。
- API リクエスト (URL、HTTP メソッド、ヘッダーなど) を構成します。
- 応答を受信して保存します。
- リソースをクリーンアップしています。
パブリック API から JSON データを取得するサンプル プログラムを次に示します。
sudo apt-get install libcurl4-openssl-dev
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
実行する手順
コードをファイルに保存します (例: get.c.
)
次のコマンドでコンパイルします:
brew install curl
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
コンパイルされたプログラムを実行します:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
// Struct to hold response data
struct Memory {
char *response;
size_t size;
};
// Callback function to handle the data received from the API
static size_t ResponseCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t totalSize = size * nmemb;
struct Memory *mem = (struct Memory *)userp;
printf(". %zu %zu\n", size, nmemb);
char *ptr = realloc(mem->response, mem->size + totalSize + 1);
if (ptr == NULL) {
printf("Not enough memory to allocate buffer.\n");
return 0;
}
mem->response = ptr;
memcpy(&(mem->response[mem->size]), contents, totalSize);
mem->size += totalSize;
mem->response[mem->size] = '<pre class="brush:php;toolbar:false">gcc get.c -o get -lcurl
ログイン後にコピー
ログイン後にコピー
';
return totalSize;
}
int main() {
CURL *curl;
CURLcode res;
struct Memory chunk;
chunk.response = malloc(1); // Initialize memory
chunk.size = 0; // No data yet
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
// Set URL of the API endpoint
char access_token[] = "your-access-token";
char slug[] = "home";
char version[]= "draft";
char url[256];
snprintf(url, sizeof(url), "https://api.storyblok.com/v2/cdn/stories/%s?version=%s&token=%s", slug, version, access_token);
// Print the URL
printf("URL: %s\n", url);
// initializing libcurl
// setting the URL
curl_easy_setopt(curl, CURLOPT_URL, url );
// Follow redirect
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
// Set callback function to handle response data
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ResponseCallback);
// Pass the Memory struct to the callback function
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
// Perform the HTTP GET request
res = curl_easy_perform(curl);
// Check for errors
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
} else {
printf("Response data size: %zu\n", chunk.size);
//printf("Response data: \n%s\n", chunk.response);
}
// Cleanup
curl_easy_cleanup(curl);
}
// Free allocated memory
free(chunk.response);
curl_global_cleanup();
return 0;
}
libcurl を使用した HTTP 応答のコールバック メカニズムを理解する
libcurl を使用して C で HTTP 応答を処理する場合、コールバック関数の動作を理解することが重要です。応答データを処理するために定義したコールバック関数 (ResponseCallback 関数など) は、1 つの HTTP 応答に対して複数回呼び出される場合があります。これがその理由と仕組みです。
コールバックが複数回呼び出されるのはなぜですか?
libcurl のコールバック メカニズムは、データを効率的かつ柔軟に処理できるように設計されています。応答全体がダウンロードされるのを待ってから処理するのではなく、libcurl は応答を小さなチャンクに分割して処理し、各チャンクが受信されるたびにコールバック関数を呼び出します。
この動作により以下が可能になります:
- 効率的なメモリ使用量: チャンクを段階的に処理することで、応答全体に大きなメモリ ブロックを事前に割り当てる必要がなくなります。
- ストリーミング処理: 各チャンクが到着したときに処理または処理できます。これは、大規模な応答をストリーミングしたり、リアルタイムでデータを処理したりする場合に役立ちます。
仕組みは?
データのチャンクをサーバーから受信するたびに、libcurl はコールバック関数を呼び出します。各チャンクのサイズは、ネットワークの状態、バッファ サイズ、libcurl の内部ロジックによって異なります。
コールバックはチャンクを蓄積し、最終的に完全な応答を再構築する必要があります。
シーケンスの例を次に示します:
- サーバーは応答の送信を開始します。
- libcurl は最初のチャンクを受信し、コールバックを呼び出します。
- コールバックはチャンクを処理または保存します。
- libcurl は次のチャンクを受信し、コールバックを再度呼び出します。
- このプロセスは、応答全体が受信されるまで継続されます。
ResponseCallback 関数のソース コードのステップバイステップの説明
ResponseCallback は、libcurl によってデータが受信されたときに呼び出される関数です。
関数の宣言
sudo apt-get install libcurl4-openssl-dev
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
-
void *content: これはサーバーから受信したデータへのポインタです。 libcurl はこのバッファを提供し、ダウンロードしたデータをバッファに埋めます。
-
size_t size と size_t nmemb: 各メモリブロックのサイズ (size) とブロック数 (nmemb) を表します。 size * nmemb を組み合わせると、このチャンクで受信したデータの合計サイズが得られます。
-
void *userp: これは、curl_easy_setopt(curl, CURLOPT_WRITEDATA, ...) を介してコールバック関数に渡されるユーザー定義のポインターです。この例では、完全な応答を格納する struct Memory オブジェクトへのポインターです。
合計データサイズを計算する
brew install curl
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
これは、1 つのブロックのサイズ (size) とブロック数 (nmemb) を乗算して、受信したデータの現在のチャンクの合計サイズを計算します。
たとえば、サーバーがそれぞれ 256 バイトのブロックを 8 つ送信する場合、totalSize は 8 * 256 = 2048 バイトになります。
ユーザーデータへのアクセス (構造体メモリ)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
// Struct to hold response data
struct Memory {
char *response;
size_t size;
};
// Callback function to handle the data received from the API
static size_t ResponseCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t totalSize = size * nmemb;
struct Memory *mem = (struct Memory *)userp;
printf(". %zu %zu\n", size, nmemb);
char *ptr = realloc(mem->response, mem->size + totalSize + 1);
if (ptr == NULL) {
printf("Not enough memory to allocate buffer.\n");
return 0;
}
mem->response = ptr;
memcpy(&(mem->response[mem->size]), contents, totalSize);
mem->size += totalSize;
mem->response[mem->size] = '<pre class="brush:php;toolbar:false">gcc get.c -o get -lcurl
ログイン後にコピー
ログイン後にコピー
';
return totalSize;
}
int main() {
CURL *curl;
CURLcode res;
struct Memory chunk;
chunk.response = malloc(1); // Initialize memory
chunk.size = 0; // No data yet
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
// Set URL of the API endpoint
char access_token[] = "your-access-token";
char slug[] = "home";
char version[]= "draft";
char url[256];
snprintf(url, sizeof(url), "https://api.storyblok.com/v2/cdn/stories/%s?version=%s&token=%s", slug, version, access_token);
// Print the URL
printf("URL: %s\n", url);
// initializing libcurl
// setting the URL
curl_easy_setopt(curl, CURLOPT_URL, url );
// Follow redirect
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
// Set callback function to handle response data
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ResponseCallback);
// Pass the Memory struct to the callback function
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
// Perform the HTTP GET request
res = curl_easy_perform(curl);
// Check for errors
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
} else {
printf("Response data size: %zu\n", chunk.size);
//printf("Response data: \n%s\n", chunk.response);
}
// Cleanup
curl_easy_cleanup(curl);
}
// Free allocated memory
free(chunk.response);
curl_global_cleanup();
return 0;
}
userp ポインタは struct Memory * にキャストされます。この構造体はメイン プログラムの前半で渡され、受信したデータを蓄積するために使用されます。
構造体メモリは次のように定義されます:
-
応答: ダウンロードされたデータを保存する動的に割り当てられた文字列。
-
size: 応答文字列の現在のサイズ。
メモリの再割り当て
static size_t ResponseCallback(void *contents, size_t size, size_t nmemb, void *userp)
ログイン後にコピー
新しいデータチャンクを収容できるように応答バッファのサイズを変更します:
-
mem->size: バッファの現在のサイズ。
-
totalSize: 新しいチャンクのサイズ。
-
1: 有効な C 文字列にするためのヌル終端文字 ( ) のためのスペース。
-
realloc: 応答バッファーのメモリを動的に再割り当てします。
割り当てが失敗した場合、realloc は NULL を返し、古いメモリは有効なままになります。
メモリ割り当てエラーの処理
size_t totalSize = size * nmemb;
ログイン後にコピー
メモリ割り当てが失敗した場合 (ptr が NULL である場合)、エラー メッセージを出力し、0 を返します。0 を返すと、libcurl に転送を中止する信号を送ります。
バッファを更新する
struct Memory *mem = (struct Memory *)userp;
ログイン後にコピー
-
mem->response = ptr: 新しく割り当てられたメモリを応答ポインタに割り当て直します。
-
memcpy: データの新しいチャンクをコンテンツからバッファーにコピーします。
-
&(mem->response[mem->size]): 新しいデータが追加されるバッファ内の場所 (現在のデータの末尾)。
-
コンテンツ: サーバーから受信したデータ。
-
totalSize: コピーするデータのサイズ。
合計サイズを更新する
struct Memory {
char *response;
size_t size;
};
ログイン後にコピー
新しいチャンクを追加した後の新しい合計サイズを反映するために、応答バッファーのサイズをインクリメントします。
応答文字列を Null で終了する
sudo apt-get install libcurl4-openssl-dev
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
有効な C 文字列にするために、応答バッファーの末尾にヌル終端文字を追加します。
これにより、応答を通常のヌル終了文字列として安全に扱うことができます。
合計サイズを返す
brew install curl
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
処理されたバイト数 (totalSize) を返します。
これは、データ チャンクが正常に処理されたことを libcurl に通知します。
API に C を選択する場合
次の場合に API の使用に C を使用します。
- パフォーマンスが重要: C は速度が重要なアプリケーションに最適です。
- システム統合: ネットワークリクエストとハードウェア操作 (PoS システムのデータフェッチなど) を組み合わせる必要があります。
- 組み込みシステム: リソースに制約のあるデバイスは、C の効率性から恩恵を受けます。
-
好奇心と探求: プログラミングが好きで、高レベルの言語で予約されていることが多いタスクを低レベルの言語で探索して自分自身に挑戦したいという理由だけで C を使用することがあります。これは、物事が内部でどのように機能するかについての理解を深めるのに最適な方法です!
結論
C で API を使用することは、今日の高レベル プログラミングの世界では型破りに思えるかもしれませんが、パフォーマンス、制御、およびシステム レベルの操作との統合が必要なシナリオにとっては強力なツールです。 libcurl のようなライブラリを使用することで、開発者は HTTP リクエストを C アプリケーションに簡単に統合し、最新の API と従来のシステムレベルのプログラミングの間のギャップを埋めることができます。
この知識があれば、API とシームレスに対話する C アプリケーションを構築でき、最新の開発ワークフローでも C が関連性を維持していることが証明されます。
以上がC での API の使用: 最新の開発者のための実践的なガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。