增加libcurl库调用百度API,与原来的的go命令执行调用API两种。libcurl涉及静态链接,考虑使用哪种?

This commit is contained in:
2025-01-14 15:14:32 +08:00
parent b45c747ba4
commit e926ce3c0b
41 changed files with 7267 additions and 10 deletions

189
libcurl.c Normal file
View File

@@ -0,0 +1,189 @@
#include "libcurl.h"
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t WriteMemoryCallback(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 == NULL) {
/* 内存不足! */
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;
}
// 获取公网IP
char *curl_get_area(char *ip)
{
char url[256] = { 0 };
snprintf(url, sizeof(url), "https://qifu.baidu.com/ip/geo/v1/district?ip=%s", ip);
CURL *curl_handle;
CURLcode res;
struct curl_slist *headers = NULL;
struct MemoryStruct chunk;
chunk.memory = malloc(1); /* 将根据上述再分配的需要增长 */
chunk.size = 0; /* 此时没有数据 */
curl_global_init(CURL_GLOBAL_ALL);
/* 初始化curl会话 */
curl_handle = curl_easy_init();
char *p = NULL;
char *buff;
p = strstr(url, "-H");
if (p) {
buff = (char *)alloca(p - url + 1);
if (buff == NULL)
perror("out of memory.");
memset(buff, 0, p - url + 1);
memcpy(buff, url, (int)(p - url - 1));
// 赋值header值
headers = curl_slist_append(headers, p + 3);
// 设置header
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl_handle, CURLOPT_URL, buff);
} else {
/* 指定要获取的URL */
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
}
/* 将所有数据发送到此函数 */
//对于同一次阻塞的curl_easy_perform而言在写完获取的数据之前会多次调用 WriteMemoryCallback
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* 将"chunk"结构传递给回调函数 */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
//对于同一次阻塞的curl_easy_perform而言在写完获取的数据之前会多次调用 WriteMemoryCallback
res = curl_easy_perform(curl_handle);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
} else {
//printf("%lu bytes retrieved\n", (unsigned long)chunk.size);
//printf("%s", chunk.memory);
;
}
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return chunk.memory;
}
// 函数用于从 cJSON 对象提取字段内容
void parse_string_field(cJSON *parent, const char *field_name, char *output, size_t max_len) {
cJSON *item = cJSON_GetObjectItemCaseSensitive(parent, field_name);
if (cJSON_IsString(item) && item->valuestring) {
strncpy(output, item->valuestring, max_len - 1);
output[max_len - 1] = '\0'; // 确保字符串以 '\0' 结尾
} else {
output[0] = '\0'; // 如果字段不存在或不是字符串,设置为空字符串
}
}
// 函数用于从 JSON 字符串解析为结构体
int parse_json_to_struct(const char *json_string, Response *response)
{
if (!response) return -1;
// 初始化结构体
memset(response, 0, sizeof(Response));
// 解析 JSON 字符串
cJSON *root = cJSON_Parse(json_string);
if (!root) {
fprintf(stderr, "Error parsing JSON: %s\n", cJSON_GetErrorPtr());
return -1;
}
// 解析字段
parse_string_field(root, "code", response->code, sizeof(response->code));
parse_string_field(root, "ip", response->ip, sizeof(response->ip));
// 如果 code 不是 "Success",直接返回
if (strcmp(response->code, "Success") != 0) {
fprintf(stderr, "Invalid code: %s\n", response->code);
cJSON_Delete(root);
return -1;
}
// 解析 data 对象
cJSON *data_item = cJSON_GetObjectItemCaseSensitive(root, "data");
if (cJSON_IsObject(data_item)) {
parse_string_field(data_item, "continent", response->data.continent, sizeof(response->data.continent));
parse_string_field(data_item, "country", response->data.country, sizeof(response->data.country));
parse_string_field(data_item, "zipcode", response->data.zipcode, sizeof(response->data.zipcode));
parse_string_field(data_item, "owner", response->data.owner, sizeof(response->data.owner));
parse_string_field(data_item, "isp", response->data.isp, sizeof(response->data.isp));
parse_string_field(data_item, "adcode", response->data.adcode, sizeof(response->data.adcode));
parse_string_field(data_item, "prov", response->data.prov, sizeof(response->data.prov));
parse_string_field(data_item, "city", response->data.city, sizeof(response->data.city));
parse_string_field(data_item, "district", response->data.district, sizeof(response->data.district));
parse_string_field(data_item, "region", response->data.region, sizeof(response->data.region));
}
snprintf(response->continent_country, 256, "%s%s", response->data.continent, response->data.country);
// 清理 JSON 对象
cJSON_Delete(root);
return 0;
}
/*
int main(int argc, char *argv[])
{
char *p = curl_get_area("1.1.1.1");
puts(p);
// 定义 Response 结构体
Response response;
// 解析 JSON 到结构体
if (parse_json_to_struct(p, &response) == 0) {
// 输出解析结果
printf("Code: %s\n", response.code);
printf("IP: %s\n", response.ip);
printf("Continent: %s\n", response.data.continent);
printf("Country: %s\n", response.data.country);
printf("ISP: %s\n", response.data.isp);
printf("Region: %s\n", response.data.region);
} else {
fprintf(stderr, "Failed to parse JSON.\n");
}
free(p);
}
*/