一个基于固定 IP地址查询天气的 C 语言程序,通过调用第三方天气 API:
一、代码功能说明
该代码是一个 基于固定 IP 地址查询天气的 C 语言程序,通过调用第三方天气 API(api.k780.com
),查询指定 IP 地址(113.66.98.219
)对应的地理位置天气信息,包括日期、天气状况、温度、风向和湿度等数据。程序通过 TCP socket 发送 HTTP 请求,解析返回的 JSON 数据并打印结果,适用于快速获取固定 IP 所在地的天气信息。
#include <stdio.h> // 标准输入输出库,用于打印和输入操作
#include <string.h> // 字符串处理库,用于字符串复制、查找等操作
#include <sys/types.h> // 系统类型定义,包含基本数据类型
#include <unistd.h> // POSIX系统调用库,用于关闭文件描述符等操作
#include <stdlib.h> // 标准库,用于内存分配(malloc/free)和程序退出
#include <fcntl.h> // 文件控制库,定义文件操作相关宏
#include <sys/stat.h> // 文件状态库,用于获取文件属性
#include <sys/socket.h> // socket编程库,用于网络通信
#include <netinet/in.h> // 网络地址结构库,定义IPv4地址格式
#include <arpa/inet.h> // 网络地址转换库,用于IP地址格式转换
#include <netdb.h> // 主机信息库,用于域名解析
#include "cJSON.h" // cJSON库,用于解析JSON格式数据extern int h_errno; // 声明外部变量h_errno,用于获取域名解析错误码// HTTP 请求函数:向指定主机发送 GET 请求并返回 JSON 数据
char* http_get_json(const char* host, const char* path) {// 解析域名到 IP 地址(DNS 解析)struct hostent* ht = gethostbyname(host); // 通过域名获取主机信息(IP地址等)if (!ht) { // 如果域名解析失败fprintf(stderr, "DNS 解析失败: %s\n", hstrerror(h_errno)); // 打印解析错误信息return NULL; // 返回NULL表示失败}// 创建 TCP socket(IPv4 协议,流式传输)int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建IPv4的TCP socketif (sockfd == -1) { // 如果socket创建失败perror("socket 创建失败"); // 打印错误原因return NULL; // 返回NULL表示失败}// 初始化服务器地址结构struct sockaddr_in addr = {.sin_family = AF_INET, // 使用IPv4地址族.sin_port = htons(80), // 设置端口为80(HTTP默认端口),转换为网络字节序.sin_addr = *(struct in_addr*)ht->h_addr // 绑定解析得到的IP地址};// 连接服务器if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { // 与服务器建立连接perror("连接服务器失败"); // 连接失败时打印错误close(sockfd); // 关闭socket释放资源return NULL; // 返回NULL表示失败}// 定义 HTTP 请求缓冲区char request[1024]; // 存储HTTP请求内容的缓冲区// 格式化 HTTP GET 请求内容(包含路径、主机等信息)snprintf(request, sizeof(request), // 拼接HTTP请求头"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", path, host);// 发送 HTTP 请求到服务器if (send(sockfd, request, strlen(request), 0) <= 0) { // 发送请求数据perror("发送请求失败"); // 发送失败时打印错误close(sockfd); // 关闭socketreturn NULL; // 返回NULL表示失败}// 分配内存用于存储服务器响应(16384 字节足够容纳一般响应)char* response = malloc(16384); // 分配响应缓冲区if (!response) { // 如果内存分配失败perror("内存分配失败"); // 打印错误close(sockfd); // 关闭socketreturn NULL; // 返回NULL表示失败}// 循环接收服务器响应,直到接收完毕int total = 0, n; // total:已接收总字节数;n:每次接收的字节数while ((n = recv(sockfd, response + total, 16384 - total - 1, 0)) > 0) { // 循环接收数据total += n; // 累加接收的字节数}response[total] = '\0'; // 给响应字符串添加结束符close(sockfd); // 关闭socket释放资源// 从响应中提取 JSON 数据char* json_start = strstr(response, "{"); // 找到JSON数据的起始位置(第一个'{')char* json_end = strrchr(response, '}'); // 找到JSON数据的结束位置(最后一个'}')if (!json_start || !json_end) { // 如果未找到JSON起止标志free(response); // 释放响应缓冲区return NULL; // 返回NULL表示失败}// 计算 JSON 数据的长度并复制size_t len = json_end - json_start + 2; // 计算JSON数据长度(包含结束符)char* json = malloc(len); // 为JSON数据分配独立内存if (!json) { // 如果内存分配失败free(response); // 释放响应缓冲区return NULL; // 返回NULL表示失败}snprintf(json, len, "%s", json_start); // 复制提取的JSON数据到新缓冲区free(response); // 释放原始响应缓冲区return json; // 返回提取的JSON数据
}// 获取天气信息(使用固定 IP:113.66.98.219)
void get_weather_by_fixed_ip() {// 固定 IP 地址:113.66.98.219const char* fixed_ip = "113.66.98.219"; // 定义要查询的固定IP地址// 构造天气查询路径(使用固定的 cityIp 参数)// 注意:这里移除了多余的 ip 参数,解决编译警告char path[1024]; // 存储API请求路径的缓冲区snprintf(path, sizeof(path), "/?app=weather.today&cityIp=IP&appkey=AppKey&sign=Sign&format=json"); // 拼接天气API的请求路径,包含固定IP和认证信息// 调用 HTTP 请求函数,获取天气的 JSON 响应char* json = http_get_json("api.k780.com", path); // 发送HTTP请求并获取JSON响应if (!json) { // 如果获取JSON失败printf("获取天气失败\n"); // 打印提示return; // 退出函数}// 解析 JSON 数据cJSON* root = cJSON_Parse(json); // 解析JSON字符串为cJSON对象if (!root) { // 如果解析失败printf("JSON 解析失败: %s\n", cJSON_GetErrorPtr()); // 打印解析错误位置free(json); // 释放JSON缓冲区return; // 退出函数}// 检查 API 调用是否成功cJSON* success = cJSON_GetObjectItem(root, "success"); // 获取"success"字段(API调用状态)if (success && strcmp(success->valuestring, "1") != 0) { // 如果调用失败(success不为"1")cJSON* msg = cJSON_GetObjectItem(root, "msg"); // 获取错误信息字段if (msg) printf("API 调用失败: %s\n", msg->valuestring); // 打印错误信息else printf("API 调用失败: 未知错误\n"); // 无错误信息时的提示cJSON_Delete(root); // 释放cJSON对象free(json); // 释放JSON缓冲区return; // 退出函数}// 提取并打印天气信息cJSON* result = cJSON_GetObjectItem(root, "result"); // 获取"result"字段(天气数据主体)if (result) { // 如果天气数据存在printf("\n===== IP: %s 对应的天气信息 =====\n", fixed_ip); // 打印标题cJSON* days = cJSON_GetObjectItem(result, "days"); // 获取日期字段if (days) printf("日期: %s\n", days->valuestring); // 打印日期else printf("日期: 未获取到\n"); // 未获取到时的提示cJSON* weather = cJSON_GetObjectItem(result, "weather"); // 获取天气状况字段if (weather) printf("天气: %s\n", weather->valuestring); // 打印天气状况else printf("天气: 未获取到\n"); // 未获取到时的提示cJSON* temperature = cJSON_GetObjectItem(result, "temperature"); // 获取温度字段if (temperature) printf("温度: %s\n", temperature->valuestring); // 打印温度else printf("温度: 未获取到\n"); // 未获取到时的提示cJSON* wind = cJSON_GetObjectItem(result, "wind"); // 获取风向字段if (wind) printf("风向: %s\n", wind->valuestring); // 打印风向else printf("风向: 未获取到\n"); // 未获取到时的提示cJSON* humidity = cJSON_GetObjectItem(result, "humidity"); // 获取湿度字段if (humidity) printf("湿度: %s\n", humidity->valuestring); // 打印湿度else printf("湿度: 未获取到\n"); // 未获取到时的提示} else { // 如果未找到天气数据printf("未找到天气数据\n"); // 打印提示}// 清理资源cJSON_Delete(root); // 释放cJSON对象,避免内存泄漏free(json); // 释放JSON缓冲区
}int main() {printf("正在查询固定 IP (113.66.98.219) 对应的天气...\n"); // 打印程序状态提示get_weather_by_fixed_ip(); // 调用函数查询天气return 0; // 程序正常结束
}
把IP换成你所在的公网IP
把AppKey和Sign换成对应获取天气平台API的
比如我用的是控制台 - NowAPI
二、编译
gcc 通过IP获取天气.c cJSON.c -o 通过IP获取天气 -lm