当前位置: 首页 > news >正文

一个基于固定 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

http://www.dtcms.com/a/320212.html

相关文章:

  • React 多语言(i18n)方案全面指南
  • 计算机英语详细总结
  • 本地化密码恢复工具的技术实现与应用边界
  • RabbitMQ面试精讲 Day 13:HAProxy与负载均衡配置
  • Git `cherry-pick` 工具汇总
  • Docker 加载镜像时出现 “no space left on device” 错误的解决方法
  • Java Lambda表达式:简洁高效的函数式编程
  • 关于光猫研究
  • 【代码随想录day 14】 力扣 101. 对称二叉树
  • 技法笔记3 | 验证交互式shell连接
  • LocalSqueeze(图片压缩工具) v1.0.4 压缩
  • 美图复现|Science:添加显著性的GO富集分析美图
  • Nuxt 4.0 完全指南:Nitro 引擎升级与 Composable API 深度解析
  • 关于Android studio调试功能使用
  • 如何选择适合中小企业的OA系统?XKOA低成本高定制化方案详解
  • 数据可视化Matplotlib
  • 【AI智能编程】Cursor IDE工具学习
  • P1037 [NOIP 2002 普及组] 产生数
  • vue-plugin-hiprint 打印模版使用
  • 【IQA技术专题】大模型评级IQA:Q-Align
  • 深入理解“进程屏蔽字“(Signal Mask)
  • 利用OpenVINO™ Day0快速部署端侧可用的MiniCPM-V4.0视觉大模型
  • 【代码随想录day 14】 力扣 226.反转二叉树
  • C语言memcpy函数详解:高效内存复制的实用工具
  • uniapp-vue2导航栏全局自动下拉变色
  • 损耗对信号质量的影响
  • OpenAI 开源 GPT-OSS:大型语言模型的开放时代正式来临!
  • HTTP请求头详解:从基础到实战
  • 当函数返回有多个返回值时,需要注意的问题 : Effective Python 第19条
  • C++ vector 扩容时到底发生了什么?