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

Day36 TCP客户端编程 HTTP协议解析 获取实时天气信息

day36 TCP客户端编程 HTTP协议解析 获取实时天气信息


一、项目目标

使用 Wireshark 抓包工具 捕获访问 www.nowapi.com(实际为 api.k780.com)获取实时天气数据的 HTTP 报文,
基于抓包结果,编写一个 TCP 客户端程序(C语言),实现以下功能:

  1. 与远程服务器建立 TCP 连接;
  2. 发送符合规范的 HTTP 请求报文;
  3. 接收服务器响应;
  4. 解析 JSON 格式的天气数据;
  5. 提取关键字段并格式化输出为指定样式。

最终输出示例如下:

2025-09-05:星期五:台北:31℃/25℃:晴转多云

二、前置知识准备

1. 网络通信流程(TCP + HTTP)

  • 使用 TCP 协议连接目标服务器(IP + 端口)
  • 手动构造 HTTP 请求报文(请求行 + 请求头)
  • 发送请求后接收响应(包含状态行、响应头、响应体)
  • 从响应体中提取 JSON 数据并解析

2. 关键函数说明

函数作用
socket()创建套接字
connect()建立 TCP 连接
send()发送数据
recv()接收数据
close()关闭连接
strstr()查找子字符串
strchr()查找字符首次出现位置
inet_addr()将点分十进制 IP 转换为网络字节序
htons()主机字节序转网络字节序(用于端口)

三、API 接口信息分析

目标网址

http://api.k780.com/?app=weather.today&cityNm=台北&appkey=77384&sign=5ac63f91d88ad9c5e08f6e513552b3f1&format=json

Remote Address(远程地址)

8.129.233.227:80

说明:该服务运行在标准 HTTP 端口 80 上,使用明文传输。


四、HTTP 请求报文结构(通过 Wireshark 抓取)

以下是浏览器访问上述 URL 时发出的完整 HTTP 请求报文:

GET /?app=weather.today&cityNm=台北&appkey=77384&sign=5ac63f91d88ad9c5e08f6e513552b3f1&format=json HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Host: api.k780.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36

注意:我们只需保留必要的字段即可完成请求。本程序中简化为以下关键字段。


五、API 响应示例(JSON 格式)

{"success": "1","result": {"weaid": "360","days": "2025-09-05","week": "星期五","cityno": "taibeixian","citynm": "台北","cityid": "101340101","temperature": "31℃/25℃","temperature_curr": "31℃","humidity": "67%","aqi": "77","weather": "晴转多云","weather_curr": "晴","weather_icon": "http://api.k780.com/upload/weather/d/0.gif","weather_icon1": "","wind": "无持续风向","winp": "1级","temp_high": "31","temp_low": "25","temp_curr": "31","humi_high": "0","humi_low": "0","weatid": "1","weatid1": "","windid": "0","winpid": "1","weather_iconid": "0"}
}

我们需要从中提取:

  • days: 日期
  • week: 星期
  • citynm: 城市名
  • temperature: 温度范围
  • weather: 天气描述

六、C语言客户端实现(cli.c)

严格按照原始代码逻辑整理,仅添加详细注释,不修改变量名、函数名、结构。

#include <arpa/inet.h>      // 提供IP地址转换函数(如inet_addr)
#include <fcntl.h>          // 文件控制相关函数(本程序未使用)
#include <netinet/in.h>     // 定义网络地址结构(如sockaddr_in)
#include <netinet/ip.h>     // IP协议相关定义(本程序未实际使用)
#include <stdio.h>          // 标准输入输出函数
#include <stdlib.h>         // 标准库函数
#include <string.h>         // 字符串处理函数(如strstr、strchr)
#include <sys/socket.h>     // 套接字相关函数(如socket、connect)
#include <sys/types.h>      // 基本系统数据类型
#include <time.h>           // 时间相关函数(本程序未使用)
#include <unistd.h>         // 系统调用函数(如close、send)// 类型别名定义:将struct sockaddr*简化为SA,方便后续使用
typedef struct sockaddr *(SA);// 向服务器发送HTTP请求命令
// 参数:conn为已建立连接的套接字描述符
int send_cmd(int conn)
{// 定义HTTP请求各部分的字符串数组char *args[7] = {NULL};// 请求行:GET方法 + 查询参数 + HTTP版本args[0] = "GET /?app=weather.today&cityNm=台北&appkey=77384&sign=5ac63f91d88ad9c5e08f6e513552b3f1&format=json HTTP/1.1\r\n";// Host头部:必须字段,指定主机域名args[1] = "Host: api.k780.com\r\n";// User-Agent:模拟Chrome浏览器请求args[2] = "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)\r\n";// Accept:客户端可接受的内容类型args[3] = "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n";// Accept-Language:语言偏好args[4] = "Accept-Language: zh-CN,zh;q=0.9\r\n";// Accept-Encoding:支持的内容编码(压缩)args[5] = "Accept-Encoding: gzip, deflate\r\n";// Connection:保持连接;结尾两个\r\n表示头部结束args[6] = "Connection: keep-alive\r\n\r\n";// 循环发送HTTP请求的各个部分int i = 0;for (i = 0; i < 7; i++){// send(套接字, 数据, 长度, 标志位)send(conn, args[i], strlen(args[i]), 0);}// 注意:原函数无返回值,但建议可加返回值表示成功
}int main(int argc, char **argv)
{// 创建TCP套接字:AF_INET(IPv4协议),SOCK_STREAM(TCP类型),0(默认协议)int conn = socket(AF_INET, SOCK_STREAM, 0);if (-1 == conn)  // 检查套接字创建是否失败{perror("socket");  // 输出错误信息return 1;          // 异常退出}// 定义并初始化服务器地址结构struct sockaddr_in ser;bzero(&ser, sizeof(ser));  // 将地址结构清零// 设置服务器地址信息ser.sin_family = AF_INET;                  // 使用IPv4协议ser.sin_port = htons(80);                  // 设置端口为80(HTTP默认端口),htons转换字节序ser.sin_addr.s_addr = inet_addr("8.129.233.227");  // 设置服务器IP地址为8.129.233.227(天气API服务器)// 与服务器建立TCP连接int ret = connect(conn, (SA)&ser, sizeof(ser));if (-1 == ret)  // 检查连接是否失败{perror("connect error\n");  // 输出错误信息return 1;                   // 异常退出}// 发送HTTP请求send_cmd(conn);// 接收服务器响应char buf[1024] = {0};  // 存储响应数据的缓冲区ret = recv(conn, buf, sizeof(buf), 0);  // 接收数据if (ret <= 0)  // 检查接收是否失败{perror("recv");  // 输出错误信息return 1;        // 异常退出}// 定义响应成功的标志char *flag1 = "HTTP/1.1 200 OK";     // HTTP响应状态码:成功char *flag2 = "\"success\":\"1\"";   // API返回成功标识// 检查响应是否成功(同时包含HTTP 200和API success=1)if (strstr(buf, flag1) && strstr(buf, flag2)){// 定位各个字段在响应中的位置(链式查找,基于前一个字段的位置)char *days = strstr(buf, "days");           // 查找days字段char *week = strstr(days, "week");          // 在days之后查找week字段char *citynm = strstr(week, "citynm");      // 在week之后查找citynm字段char *temperature = strstr(citynm, "temperature");  // 查找temperature字段char *weather = strstr(temperature, "weather");      // 查找weather字段char *end = NULL;  // 用于标记字段值的结束位置// 提取days字段值days += 7;  // 跳过"days":"(7个字符)end = strchr(days, '"');  // 查找结束双引号*end = '\0';  // 替换为字符串结束符// 提取week字段值week += 7;  // 跳过"week":"(7个字符)end = strchr(week, '"');*end = '\0';// 提取citynm字段值citynm += 9;  // 跳过"citynm":"(9个字符)end = strchr(citynm, '"');*end = '\0';// 提取temperature字段值temperature += 14;  // 跳过"temperature":"(14个字符)end = strchr(temperature, '"');*end = '\0';// 提取weather字段值weather += 10;  // 跳过"weather":"(10个字符)end = strchr(weather, '"');*end = '\0';// 打印解析后的天气信息(按要求格式输出)printf("%s:%s:%s:%s:%s\n", days, week, citynm, temperature, weather);}close(conn);  // 关闭套接字,释放连接资源return 0;  // 程序正常退出
}

七、程序运行理想结果

假设网络正常、API 可用,运行程序后应输出如下内容:

2025-09-05:星期五:台北:31℃/25℃:晴转多云

注:实际输出取决于 API 当前返回的数据,若城市或时间变化,输出也会相应更新。


八、关键点总结

模块要点
TCP连接使用 socket() + connect() 建立与 8.129.233.227:80 的连接
HTTP请求构造手动拼接请求行和请求头,注意 \r\n 结尾与双换行结束头部
数据接收使用 recv() 接收响应,注意缓冲区大小
响应解析使用 strstr() 定位字段,strchr() 截取值,手动解析 JSON(简易方式)
安全性未处理分包、粘包、编码压缩等问题,仅适用于简单场景
扩展建议可引入 JSON 解析库(如 cJSON)提升健壮性

九、Wireshark 抓包提示(图片注释保留)

【图片注释:使用 Wireshark 捕获访问 api.k780.com 时的 TCP 与 HTTP 数据包,观察三次握手、HTTP 请求/响应、四次挥手全过程】

  • 过滤条件可输入:ip.addr == 8.129.233.227 && tcp.port == 80
  • 观察 TCP 三次握手(SYN, SYN-ACK, ACK)
  • 查看 HTTP GET 请求内容
  • 分析服务器返回的 JSON 响应体
  • 注意 Content-Length 与实际数据长度是否一致

十、注意事项

  • 本程序为简化版,未处理 gzip 压缩内容(服务器可能返回压缩数据)
  • 若服务器启用 HTTPS(端口443),需使用 OpenSSL 库进行加密通信
  • 实际开发中建议使用 libcurl 等成熟库替代手动 TCP 编程
  • JSON 解析建议使用专业库避免错误(如字段顺序变动导致 strstr 失效)

本日所学知识点涵盖:

  • TCP 客户端编程
  • HTTP 协议原理与报文构造
  • 字符串处理(strstr, strchr
  • 结构化数据提取(简易 JSON 解析)
  • 网络调试工具使用(Wireshark)
  • 系统调用接口应用(socket, connect, send, recv, close)

文章转载自:

http://QWGb34fW.Lhsdf.cn
http://9sop1RJU.Lhsdf.cn
http://GqkpNTrm.Lhsdf.cn
http://tfroIbc9.Lhsdf.cn
http://6iQySyip.Lhsdf.cn
http://pXyifMGo.Lhsdf.cn
http://WOi1M254.Lhsdf.cn
http://1624Iuxu.Lhsdf.cn
http://sr0fFDTw.Lhsdf.cn
http://V3k4RY2m.Lhsdf.cn
http://OxYCatdy.Lhsdf.cn
http://pnWdf2jT.Lhsdf.cn
http://WsOvm2hl.Lhsdf.cn
http://m75o1EXV.Lhsdf.cn
http://mP1bGazw.Lhsdf.cn
http://v7opvzVR.Lhsdf.cn
http://mViqwBAM.Lhsdf.cn
http://qCarheKx.Lhsdf.cn
http://xyGQ0rYu.Lhsdf.cn
http://Is1n4OqH.Lhsdf.cn
http://BxTMie89.Lhsdf.cn
http://UZEKad1i.Lhsdf.cn
http://Jrlc4DIo.Lhsdf.cn
http://OH2fsIZh.Lhsdf.cn
http://1j6O6DuQ.Lhsdf.cn
http://ybzwUTbA.Lhsdf.cn
http://xjW6p5rK.Lhsdf.cn
http://riv7ESGh.Lhsdf.cn
http://Jlv4RH02.Lhsdf.cn
http://9ObaxRue.Lhsdf.cn
http://www.dtcms.com/a/367888.html

相关文章:

  • 分享个C++线程池的实现源码
  • 143. 重排链表
  • 实习结束,秋招开启
  • MySQL集群高可用架构---mysql高可用之组复制 (MGR)
  • nginx采用反向代理的时候使用变量的坑
  • Kali搭建sqli-labs靶场
  • 【硬件笔记】负载是如何烧MOS的?
  • 从 Prompt 到 Context:LLM OS 时代的核心工程范式演进
  • 设计模式从入门到精通之(六)策略模式
  • 【译】GitHub Copilot for Azure(预览版)已经在 Visual Studio 2022 中推出
  • langchain 提示模版 PromptTemplate
  • Ubuntu开发笔记:1.常见操作指令
  • DDD+WebAPI实战
  • 狗都能看懂的HunYuan3D 1.0详解
  • CodeQL(Mac)安装与测试(Visual Studio)简明指南
  • Next.js 介绍:为什么选择它来构建你的下一个 Web 应用?
  • $attrs学习
  • 无定位更安全:5G 高清视频终端的保密场景适配之道
  • GitHub 热榜项目 - 日榜(2025-09-05)
  • 一文看懂什么是GaN HEMT以及其工艺流程(氮化镓高电子迁移率晶体管)
  • 【AI编程工具】快速搭建图书管理系统
  • 安卓学习 之 EditText 控件
  • 2025职教技能大赛汽车制造与维修赛道速递-产教融合实战亮剑​
  • java面试中经常会问到的zookeeper问题有哪些(基础版)
  • 光伏项目无人机踏勘--如何使用无人机自动航线规划APP
  • jenkins加docker 部署项目
  • linux离线安装elasticsearch8.19.3
  • Jenkins环境搭建与使⽤
  • Jenkins 监控方案:Prometheus + Grafana 实践
  • 【论文阅读】Security of Language Models for Code: A Systematic Literature Review