如今,使用 Web API 是在应用程序之间交换数据的常见做法。关于使用 JavaScript、Python 或 PHP 等语言的 API 的教程有很多,但 C(通常与系统级编程相关)很少被考虑用于此目的。然而,C 完全有能力处理 API 请求,使其成为销售点 (PoS) 系统、物联网设备或嵌入式应用程序等场景的可行选择,在这些场景中,C 已经因其效率和低级控制而被使用。
本文探讨了如何利用 libcurl 库使用 C 语言的 API。最后,您将了解如何使用 C 从 API 获取和处理数据,以及为什么这种方法即使在现代开发中也有意义。
虽然高级语言主导 Web 开发,但 C 仍然是在特定用例中使用 API 的实用选择:
要使用 C 语言的 API,libcurl 是首选库。它是一个开源、可移植且功能丰富的库,用于处理通过 HTTP、HTTPS、FTP 等的网络请求。它支持:
让我们逐步了解使用 C 语言使用 API 的过程,重点关注获取 JSON 数据的实际示例。
要使用 libcurl,您需要在系统上安装它。对于大多数 Linux 发行版,这可以通过以下方式完成:
sudo apt-get install libcurl4-openssl-dev
在 Windows 上,您可以从 libcurl 网站下载预编译的二进制文件:https://curl.se/download.html
在 macOS 上,如果您使用 Homebrew,可以通过
安装它
brew install curl
从 API 获取数据的简单 C 程序涉及以下组件:
这是一个从公共 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; }
在 C 中使用 libcurl 处理 HTTP 响应时,了解回调函数的行为非常重要。您定义的用于处理响应数据的回调函数(例如 ResponseCallback 函数)可能会针对单个 HTTP 响应调用多次。这就是为什么以及它是如何工作的。
libcurl 中的回调机制旨在高效、灵活地处理数据。 libcurl 不会在处理整个响应之前等待下载整个响应,而是以较小的块处理响应,并在收到每个块时调用回调函数。
此行为允许:
它是如何工作的?
每次从服务器接收到一块数据时,libcurl 都会调用您的回调函数。每个块的大小取决于网络条件、缓冲区大小和 libcurl 的内部逻辑。
回调必须累积块,最终重建完整的响应。
这是一个示例序列:
ResponseCallback 是 libcurl 接收数据时调用的函数。
sudo apt-get install libcurl4-openssl-dev
brew install curl
通过将一个块的大小 (size) 乘以块的数量 (nmemb) 来计算当前接收到的数据块的总大小。
例如,如果服务器发送 8 个块,每个块 256 字节,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 *。该结构体已在主程序中前面传递,用于累积接收到的数据。
结构体 Memory 定义为:
./get
static size_t ResponseCallback(void *contents, size_t size, size_t nmemb, void *userp)
调整响应缓冲区的大小以容纳新的数据块:
如果分配失败,realloc返回NULL,旧内存仍然有效。
size_t totalSize = size * nmemb;
如果内存分配失败(因此 ptr 为 NULL),则打印错误消息并返回 0。返回 0 表示 libcurl 中止传输。
struct Memory *mem = (struct Memory *)userp;
struct Memory { char *response; size_t size; };
增加响应缓冲区的大小以反映附加新块后的新总大小。
sudo apt-get install libcurl4-openssl-dev
在响应缓冲区末尾添加一个空终止符,使其成为有效的 C 字符串。
这确保了响应可以被安全地视为常规的空终止字符串。
brew install curl
返回已处理的字节数(totalSize)。
这向 libcurl 发出信号,表明数据块已成功处理。
在以下情况下使用 C 来使用 API:
在当今的高级编程世界中,使用 C 语言的 API 似乎不合常规,但对于需要性能、控制以及与系统级操作集成的场景来说,它是一个强大的工具。通过使用 libcurl 等库,开发人员可以轻松地将 HTTP 请求集成到 C 应用程序中,从而弥合现代 API 和传统系统级编程之间的差距。
有了这些知识,您就可以构建与 API 无缝交互的 C 应用程序,证明 C 即使在现代开发工作流程中仍然具有相关性。
以上是使用 C 语言 API:现代开发人员的实用指南的详细内容。更多信息请关注PHP中文网其他相关文章!