#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; } char *GetLocalAddr(char *url) { 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; } // 获取公网IP char *CurlGetIpArea(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 (!json_string || !response) { fprintf(stderr, "Invalid input parameters!\n"); 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()); printf("%s\n", json_string); 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)); } // ----------- 拼接 continent_country --------------- if (snprintf(response->continent_country, sizeof(response->continent_country), "%s%s", response->data.continent, response->data.country) >= sizeof(response->continent_country)) { fprintf(stderr, "continent_country truncated!\n"); } //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); } */