C语言获取JSON数据:从网络请求到数据解析**
在C语言中直接请求和解析JSON数据,相较于一些高级语言(如Python、JavaScript)而言,确实需要更多的手动操作和依赖第三方库,因为C语言本身并没有内置对JSON和网络请求的直接支持,通过结合一些成熟的库,我们依然可以在C语言中高效地实现这一功能,本文将详细介绍如何使用C语言进行HTTP请求以获取JSON数据,并解析返回的JSON字符串。
整个过程大致可以分为两个主要步骤:
- 发送HTTP请求:从指定的URL获取JSON数据。
- 解析JSON数据:将获取到的JSON字符串解析成C语言中的数据结构(如结构体、数组等)。
第一步:发送HTTP请求获取JSON数据
在C语言中,发送HTTP请求常用的库有:
- libcurl:功能强大且广泛使用的客户端URL传输库,支持多种协议,包括HTTP、HTTPS、FTP等,这是最推荐的选择。
- WinINet:仅适用于Windows平台,是Windows API的一部分。
- POSIX sockets:更底层,需要手动处理HTTP协议细节,较为复杂。
这里我们重点介绍libcurl的使用。
安装libcurl
在使用libcurl之前,需要确保它已经安装在你的系统上。
- Linux (Ubuntu/Debian):
sudo apt-get install libcurl4-openssl-dev - Linux (Fedora/CentOS):
sudo dnf install libcurl-devel - Windows: 可以从libcurl官网下载预编译的二进制包和开发包,并将其包含路径和库路径添加到你的开发环境中(如Visual Studio)。
使用libcurl发送GET请求获取JSON数据
以下是一个使用libcurl发送GET请求并获取JSON响应的简单示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
// 回调函数,用于处理libcurl接收到的数据
size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if(!ptr) {
/* 内存分配失败 */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
struct MemoryStruct {
char *memory;
size_t size;
};
int main(void) {
CURL *curl;
CURLcode res;
struct MemoryStruct chunk;
chunk.memory = malloc(1); // 初始分配1字节
chunk.size = 0;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl) {
// 示例API,返回JSON数据
const char *url = "https://jsonplaceholder.typicode.com/posts/1";
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
// 设置User-Agent,有些服务器会要求
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
// 如果是HTTPS,可能需要忽略SSL证书验证(仅测试用,生产环境不推荐)
// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
// 发送请求
res = curl_easy_perform(curl);
// 检查错误
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
} else {
// 获取HTTP响应码
long response_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
printf("HTTP response code: %ld\n", response_code);
printf("Received JSON data:\n%s\n", chunk.memory);
}
// 清理
curl_easy_cleanup(curl);
}
free(chunk.memory);
curl_global_cleanup();
return 0;
}
代码说明:
#include <curl/curl.h>:包含libcurl的头文件。WriteCallback:这是一个回调函数,libcurl在接收到数据时会调用它,我们将接收到的数据追加到MemoryStruct结构体的memory字段中。MemoryStruct:用于存储从服务器接收到的原始数据。curl_easy_init():初始化一个curl easy handle。curl_easy_setopt():设置curl的各种选项,如URL、回调函数、写入数据等。curl_easy_perform():执行请求。curl_easy_cleanup():清理curl easy handle。curl_global_init()和curl_global_cleanup():全局初始化和清理。
编译时需要链接libcurl库:
- Linux:
gcc -o json_request json_request.c -lcurl - Windows (Visual Studio): 在项目设置中添加libcurl的库路径和libcurl.lib。
第二步:解析JSON数据
获取到JSON字符串后,我们需要将其解析成C语言可以方便操作的数据结构,常用的C语言JSON库有:
- cJSON:轻量级、易于使用的C JSON解析器和生成器。
- Jansson:功能丰富、性能较好的C JSON库。
- json-c:另一个流行的C JSON库。
这里我们以cJSON为例进行介绍。
安装cJSON
- Linux (Ubuntu/Debian):
sudo apt-get install libcjson-dev - Linux (Fedora/CentOS):
sudo dnf install libcjson-devel - Windows: 从cJSON官网下载源码,编译成静态库或动态库,并配置到开发环境。
- 或者直接将cJSON的源文件(cJSON.c和cJSON.h)加入到你的项目中。
使用cJSON解析JSON数据
假设我们已经通过libcurl获取了前面示例中的JSON字符串:
{"userId": 1, "id": 1, "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}
我们可以使用cJSON来解析它:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 假设已经包含了libcurl的相关代码和获取了chunk.memory中的JSON字符串
#include "cJSON.h" // 确保cJSON.h在包含路径中
void parse_json(const char *json_string) {
cJSON *root = NULL;
cJSON *userId = NULL;
cJSON *id = NULL;
cJSON *title = NULL;
cJSON *body = NULL;
// 解析JSON字符串
root = cJSON_Parse(json_string);
if (root == NULL) {
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL) {
fprintf(stderr, "Error before: %s\n", error_ptr);
}
return;
}
// 获取字段值
userId = cJSON_GetObjectItemCaseSensitive(root, "userId");
id = cJSON_GetObjectItemCaseSensitive(root, "id");= cJSON_GetObjectItemCaseSensitive(root, "title");
body = cJSON_GetObjectItemCaseSensitive(root, "body");
// 检查字段是否存在并打印
if (cJSON_IsNumber(userId) && cJSON_IsNumber(id) && cJSON_IsString(title) && cJSON_IsString(body)) {
printf("User ID: %d\n", userId->valueint);
printf("ID: %d\n", id->valueint);
printf("Title: %s\n", title->valuestring);
printf("Body: %s\n", body->valuestring);
} else {
fprintf(stderr, "Failed to parse JSON fields.\n");
}
// 释放JSON对象
cJSON_Delete(root);
}
// 假设chunk.memory是libcurl获取到的JSON字符串
// int main() {
// // ... libcurl获取数据的代码 ...
// if (chunk.size > 0) {
// parse_json(chunk.memory);
// }
// // ... 清理代码 ...
// return 0;
// }
代码说明:
cJSON_Parse():将JSON字符串解析成一个cJSON对象树。cJSON_GetObjectItemCaseSensitive():根据键名获取JSON对象



还没有评论,来说两句吧...