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

Linux:网络编程-基于HTTP协议的天气预报查询系统开发详解

目录

1.系统架构与核心功能

2.关键技术实现

2.1网络通信

2.2JSON数据解析

3.完整工作流程

4.技术亮点

5.成果展示

5.1代码

5.2使用示例

6.扩展方向


引言

在嵌入式开发或网络编程学习中,通过Socket编程实现与Web API的交互是一项基础而重要的技能。本文介绍了我开发的一个基于HTTP协议的天气预报查询系统。该系统通过以下流程获取数据:

  1. 建立TCP连接至远程服务器(nowapi提供的API接口)

  2. 发送符合规范的HTTP请求

  3. 接收并解析JSON格式的响应数据

  4. 提取并展示指定城市的实时天气及未来天气预报

下文将详细解析系统实现的技术细节,包括Socket通信机制、HTTP协议处理、JSON数据解析等核心模块的实现方案。

1.系统架构与核心功能

该系统采用模块化设计,主要包含以下功能模块:

  1. 网络通信模块:建立TCP连接并发送HTTP请求

  2. 数据解析模块:处理JSON格式的天气数据

  3. 数据展示模块:格式化输出天气信息

程序通过Weather结构体存储天气数据:

typedef struct { char city[32]; char date[32]; char week[32]; char weather[32]; char max_temperature[4]; char min_temperature[4]; char wind_direction[32]; char wind_power[8]; char Humidity[8]; } Weather;

2.关键技术实现

2.1网络通信

  • 使用socket建立TCP连接

  • 通过connect连接nowapi服务器(103.205.5.206:80)

  • 构造符合HTTP协议的GET请求

int CreateTcpConnection(const char *pip, int port) { int sockfd = socket(AF_INET, SOCK_STREAM, 0); // ...套接字创建和连接逻辑 } int SendHttpRequest(int sockfd, const char *purl) { sprintf(sendbuf, "GET %s HTTP/1.1\r\n", purl); // ...HTTP头构造逻辑 }

2.2JSON数据解析

  • 使用cJSON库解析API返回的JSON数据

  • 分别处理当天和未来天气数据

  • 错误处理机制确保数据有效性

int Analys_today(char* json_string) { cJSON *root = cJSON_Parse(json_string); cJSON *success = cJSON_GetObjectItem(root, "success"); if(0 == strcmp(success->valuestring,"0")) { printf("该地点未收到天气数据\n"); exit(0); } // ...数据提取逻辑 }

2.3用户交互与展示

  • 终端交互式输入城市名称

  • 格式化输出当天和未来天气信息

  • 清晰的数据分隔线提升可读性

int ShowToday() { printf("------------------------------------------------\n"); printf("城市 : %s\n",Today.city); printf("日期 : %s\n",Today.date); // ...其他天气信息输出 printf("------------------------------------------------\n"); }

3.完整工作流程

  1. 用户输入目标城市名称

  2. 程序创建TCP连接并发送天气请求:

    • 当天天气:/?app=weather.today&weaid=城市名...

    • 未来天气:/?app=weather.future&weaid=城市名...

  3. 接收并解析JSON格式的天气数据

  4. 格式化输出天气信息:

    • 当天天气详情

    • 未来7天天气预报

4.技术亮点

  1. 高效的网络通信:直接使用socket进行TCP通信,避免依赖外部库

  2. 健壮的错误处理:检测API返回的success字段,无效数据时优雅退出

  3. 内存管理:使用cJSON_Delete释放解析后的JSON对象

  4. 数据封装:Weather结构体清晰组织天气数据

5.成果展示

5.1代码

#include "head.h" #include "cJSON.h" typedef struct { char city[32]; char date[32]; char week[32]; char weather[32]; char max_temperature[4]; char min_temperature[4]; char wind_direction[32]; char wind_power[8]; //风力级数 char Humidity[8]; //湿度 }Weather; Weather Today ; Weather FutureDay[7] = {0}; int Num_future_days = 0; int CreateTcpConnection(const char *pip, int port) { int ret = 0; int sockfd = 0; struct sockaddr_in seraddr; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == sockfd) { perror("fail to socket"); return -1; } seraddr.sin_family = AF_INET; seraddr.sin_port = htons(port); seraddr.sin_addr.s_addr = inet_addr(pip); ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr)); if (-1 == ret) { perror("fail to connect"); return -1; } return sockfd; } int SendHttpRequest(int sockfd, const char *purl) //发送http请求 { char sendbuf[4096] = {0}; ssize_t nret = 0; sprintf(sendbuf, "GET %s HTTP/1.1\r\n", purl); sprintf(sendbuf, "%sHost: api.k780.com\r\n", sendbuf); sprintf(sendbuf, "%sUser-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0\r\n", sendbuf); sprintf(sendbuf, "%sAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n", sendbuf); sprintf(sendbuf, "%sAccept-Language: en-US,en;q=0.5\r\n", sendbuf); sprintf(sendbuf, "%sAccept-Encoding: gzip, deflate\r\n", sendbuf); sprintf(sendbuf, "%sConnection: keep-alive\r\n", sendbuf); sprintf(sendbuf, "%sUpgrade-Insecure-Requests: 1\r\n", sendbuf); sprintf(sendbuf, "%s\r\n", sendbuf); nret = send(sockfd, sendbuf, strlen(sendbuf), 0); if (-1 == nret) { perror("fail to send"); return -1; } return 0; } int RecvHttpRespone(int sockfd, char *ptmpbuff, int maxlen) { ssize_t nret = 0; nret = recv(sockfd, ptmpbuff, maxlen, 0); if (-1 == nret) { perror("fail to recv"); return -1; } //printf("%s\n\n",ptmpbuff); return 0; } int ShowToday( ) { printf("----------------------今日天气-------------------\n"); printf("------------------------------------------------\n"); printf("城市 : %s\n",Today.city); printf("日期 : %s\n",Today.date); printf("星期 : %s\n",Today.week); printf("天气 : %s\n",Today.weather); printf("最高温度 :%s℃\n",Today.max_temperature); printf("最低温度 :%s℃\n",Today.min_temperature); printf("湿度 : %s\n",Today.Humidity); printf("风向 : %s\n",Today.wind_direction); printf("风力 : %s\n",Today.wind_power); printf("------------------------------------------------\n"); return 0; } int ShowFuture() { printf("----------------------未来天气-------------------\n"); // 遍历数组 for(int i = 1; i < Num_future_days; i++) { printf("------------------------------------------------\n"); printf("日期 : %s\n",FutureDay[i].date); printf("星期 : %s\n",FutureDay[i].week); printf("天气 : %s\n",FutureDay[i].weather); printf("最高温度 : %s℃\n",FutureDay[i].max_temperature); printf("最低温度 : %s℃\n",FutureDay[i].min_temperature); printf("风向 : %s\n",FutureDay[i].wind_direction); printf("风力 : %s\n",FutureDay[i].wind_power); printf("------------------------------------------------\n"); } return 0; } // 解析JSON字符串 int Analys_today(char* json_string) { cJSON *root = cJSON_Parse(json_string); if (!root) { printf("解析失败\n"); return -1; } cJSON *success = cJSON_GetObjectItem(root, "success"); if(0 == strcmp(success -> valuestring,"0")) { printf("================================================\n"); printf("该地点未收到天气数据\n"); printf("================================================\n"); exit(0);//优雅退出进程 } cJSON *result = cJSON_GetObjectItem(root, "result"); // 获取今日的结果 strcpy(Today.date , cJSON_GetObjectItem(result, "days")->valuestring); strcpy(Today.city , cJSON_GetObjectItem(result, "citynm")->valuestring); strcpy(Today.week , cJSON_GetObjectItem(result, "week")->valuestring); strcpy(Today.weather , cJSON_GetObjectItem(result, "weather")->valuestring); strcpy(Today.wind_direction , cJSON_GetObjectItem(result, "wind")->valuestring); strcpy(Today.wind_power, cJSON_GetObjectItem(result, "winp")->valuestring); strcpy(Today.Humidity , cJSON_GetObjectItem(result, "humidity")->valuestring); strcpy(Today.max_temperature , cJSON_GetObjectItem(result, "temp_high")->valuestring); strcpy(Today.min_temperature , cJSON_GetObjectItem(result, "temp_low")->valuestring); cJSON_Delete(root); return 0; } int Analys_future(char* json_string) { // 解析JSON字符串 char tmp[32] = {0}; cJSON *root = cJSON_Parse(json_string); cJSON *result = cJSON_GetObjectItem(root, "result");//遍历数组 if (!root) { printf("解析失败\n"); return -1; } // 获取未来的结果 // 遍历数组 Num_future_days = cJSON_GetArraySize(result); for (int i = 0; i < Num_future_days; i++) { cJSON *futureDay_tmp = cJSON_GetArrayItem(result, i);//遍历数组 //获取未来天气结果 strcpy(FutureDay[i].date , cJSON_GetObjectItem(futureDay_tmp, "days")->valuestring); strcpy(FutureDay[i].week , cJSON_GetObjectItem(futureDay_tmp, "week")->valuestring); strcpy(FutureDay[i].weather , cJSON_GetObjectItem(futureDay_tmp, "weather")->valuestring); strcpy(FutureDay[i].wind_direction , cJSON_GetObjectItem(futureDay_tmp, "wind")->valuestring); strcpy(FutureDay[i].wind_power, cJSON_GetObjectItem(futureDay_tmp, "winp")->valuestring); strcpy(FutureDay[i].max_temperature , cJSON_GetObjectItem(futureDay_tmp, "temp_high")->valuestring); strcpy(FutureDay[i].min_temperature , cJSON_GetObjectItem(futureDay_tmp, "temp_low")->valuestring); } // 释放内存 cJSON_Delete(root); return 0; } int main(void) { int sockfd = 0; char tmpbuff[40960] = {0}; char City[32] = {0}; char URL[256] = {0}; char* j_start = NULL; printf("请输入您要查看的城市:\n"); scanf("%s",City); //发送请求 sockfd = CreateTcpConnection("103.205.5.206", 80); sprintf(URL,"/?app=weather.today&weaid=%s&appkey=78692&sign=4fc12179d774cba5500d9d7c56e92f74&format=json",City); SendHttpRequest(sockfd, URL); RecvHttpRespone(sockfd, tmpbuff, sizeof(tmpbuff));//接收结果 //close(sockfd); //解析结果 j_start = strstr(tmpbuff, "\r\n\r\n"); j_start += 4; // 跳过"\r\n\r\n" for(;*j_start != '{';j_start++); //输出结果 Analys_today(j_start); printf("================================================\n"); ShowToday(); //发送请求 memset(tmpbuff,0,sizeof(tmpbuff)); memset(URL,0,sizeof(URL)); sprintf(URL,"/?app=weather.future&weaid=%s&appkey=78692&sign=4fc12179d774cba5500d9d7c56e92f74&format=json",City); SendHttpRequest(sockfd, URL); RecvHttpRespone(sockfd, tmpbuff, sizeof(tmpbuff));//接收结果 //解析结果 j_start = strstr(tmpbuff, "\r\n\r\n"); j_start += 4; // 跳过"\r\n\r\n" for(;*j_start != '{';j_start++); //输出结果 Analys_future(j_start); ShowFuture(); printf("================================================\n"); close(sockfd); return 0; }

5.2使用示例

// ./weather_program 请输入您要查看的城市: 泸州 ================================================ ----------------------今日天气------------------- ------------------------------------------------ 城市 : 泸州 日期 : 2026-03-08 星期 : 星期日 天气 : 小雨转中雨 最高温度 :16℃ 最低温度 :12℃ 湿度 : 67% 风向 : 东北风 风力 : 2级 ------------------------------------------------ ----------------------未来天气------------------- ------------------------------------------------ 日期 : 2026-03-09 星期 : 星期一 天气 : 小雨 最高温度 : 17℃ 最低温度 : 10℃ 风向 : 无持续风向 风力 : 小于3级 ------------------------------------------------ ------------------------------------------------ 日期 : 2026-03-10 星期 : 星期二 天气 : 晴 最高温度 : 24℃ 最低温度 : 11℃ 风向 : 无持续风向 风力 : 小于3级 ------------------------------------------------ ------------------------------------------------ 日期 : 2026-03-11 星期 : 星期三 天气 : 晴转多云 最高温度 : 25℃ 最低温度 : 14℃ 风向 : 无持续风向 风力 : 小于3级 ------------------------------------------------ ------------------------------------------------ 日期 : 2026-03-12 星期 : 星期四 天气 : 多云转小雨 最高温度 : 25℃ 最低温度 : 15℃ 风向 : 无持续风向 风力 : 小于3级 ------------------------------------------------ ------------------------------------------------ 日期 : 2026-03-13 星期 : 星期五 天气 : 阵雨转小雨 最高温度 : 24℃ 最低温度 : 12℃ 风向 : 无持续风向 风力 : 小于3级 ------------------------------------------------ ------------------------------------------------ 日期 : 2026-03-14 星期 : 星期六 天气 : 小雨 最高温度 : 12℃ 最低温度 : 10℃ 风向 : 无持续风向 风力 : 小于3级 ------------------------------------------------ ================================================

6.可扩展方向

  1. 增加天气图标可视化

  2. 添加空气质量指数(AQI)查询

  3. 实现多语言支持

  4. 开发图形界面版本

📝 写在最后

这个小程序其实是我闲来无事自己折腾着玩写出来的,纯粹出于兴趣和对C语言、网络编程的一点学习热情。技术上肯定还有很多不成熟的地方,代码也可能写得比较“糙”,把它分享出来,主要是想:

  1. 记录一下自己的学习过程,算是做个笔记。

  2. 和大家交流交流技术。如果你对C语言、网络请求、JSON解析这些感兴趣,或者觉得这个思路有点意思,欢迎一起探讨!

  3. 抛砖引玉。代码里肯定有不少可以改进、优化的地方,或者有更好的实现方式。非常欢迎大家提出宝贵的意见、建议或者批评!​ 相互学习,共同进步嘛。

所以,这完全是一个供学习交流的小玩意儿。如果你觉得它还有点用,或者能给你带来一点启发,那我就很开心了!当然,也欢迎你基于这个思路去折腾出更酷的东西!

欢迎交流,欢迎指正!​ 😊

http://www.jsqmd.com/news/453837/

相关文章:

  • Kafka自动提交把消息吃了:一次“已提交未处理”+重平衡导致丢数和爆堆积
  • 把 AI助手搬进飞书!OpenClaw接入完整指南
  • 2026广州GEO优化公司排名TOP5|本地实力派盘点,亚森SEO稳居榜首!
  • 周红伟:2026年OpenClaw最佳实践:一键部署+免费API配置+集成8大股票分析Skills及避坑指南
  • matlab麻雀搜索算法(SSA)优化BP神经网络,权值和阈值,一个压缩包共三个文件,包括有数...
  • 深度学习在财务报表舞弊识别中的应用:构建一个智能审计助手
  • Rokid UXR 的手势追踪虚拟中更真实的手实战开发【含 工程源码 和 最终完成APK】
  • 开发者的临时文件自动化工具:提升效率与系统整洁度的关键方案
  • 别只当它是管家,RT-Thread 会自己生长
  • 权威解读:企业合作政策如何让非科班生通过国内AI认证实现“弯道超车”?
  • 2026年房山及燕山地区装修套餐全解析:五大优质服务商深度推荐 - 品牌2026
  • openclaw gateway status报错且gate无法正常运行解决办法
  • 无数绘画测试!Nano Banana 2 vs GPT Image 1.5,谁才是最厉害的模型
  • LeetCode-35.搜索插入位置
  • 基于javaweb的作业智能推荐系统的设计与实现
  • 2026超纯水机厂家推荐:进口与国产品牌实力对比 - 品牌推荐大师
  • 光学神经网络:进展与挑战(Optical Neural Networks: Progress and Challenges)
  • 如何本地部署大模型(以PaddleOCR-VL-1.5为例)
  • 2026年房山环保家装公司怎么选?五家实力装企深度解析 - 品牌2026
  • Gemini 3.1 Flash Image Preview (Nano Banana 2) 深度技术评测与极速接入指南
  • 2026最新25万级SUV智驾领先双能源车型推荐!权威榜单发布 - 十大品牌榜
  • ESP-IDF Chip revision问题解决方案
  • 2026年 信捷电气厂家推荐排行榜:江苏/安徽/上海/苏州/常州/合肥/芜湖/南京/镇江/南通/徐州/无锡,专业自动化解决方案与技术创新实力深度解析 - 品牌企业推荐师(官方)
  • 留学申请服务费用多少,考虑性价比,澳洲、马来西亚有啥好选择 - mypinpai
  • ARM Cortex-R52 内核详解(三)——异常处理机制
  • 【hello-agent】Plan-and-Solve
  • 2026 电池放电仪、电池内阻仪厂家:技术与口碑的双重认证 - 深度智识库
  • 计算机毕业设计源码:基于Python的智能推荐电商平台 Django Vue3 Scrapy爬虫 协同过滤推荐算法 大模型 购物 多模态 deepseek agent(建议收藏)✅
  • 2026最新25万级SUV/25万级SUV智驾/25万级SUV轿跑/25万级SUV双能源车型推荐:智驾领跑,实力重塑出行标杆 - 十大品牌榜
  • 2026年广州响应式网站建设,谁才是真正的口碑之选?