一,获取报文数据

复制这个网址 去掉s

并且获取appkey和sign 再替换到到上图二的网址中,打开修改好的网址
这样子我们就可以用了

点击network 找到右下角的ip地址和端口
ip地址:103.205.5.206 端口:80
点击row完全展开,复制全部的报文去写字本(方便等会编辑好放进代码中)
二,要求
实现下图的功能

三,编程思路
1,模块图
项目是干嘛的
用 C 语言手动发 HTTP 请求,把服务器返回的 JSON 字符串里的天气数据抠出来打印。
整体流程:Socket 建连接 → 发 HTTP 请求 → 收 JSON 响应 → 手动解析字段 → 打印
一、网络连接怎么写(每次查询都要走这套)
cs
// 1. 建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 2. 填服务器地址
struct sockaddr_in ser;
bzero(&ser, sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(80); // HTTP 端口 80
ser.sin_addr.s_addr = inet_addr("103.205.5.206"); // k780 服务器 IP
// 3. 连接(注意强转,typedef struct sockaddr* SA 是为了这里)
connect(sockfd, (SA)&ser, sizeof(ser));
// 4. 发请求 / 收响应
send(sockfd, buf, strlen(buf), 0);
bzero(buf, sizeof(buf));
recv(sockfd, buf, sizeof(buf), 0);
// 5. 用完关掉!(get_weather 忘写了这行,会泄漏 fd)
close(sockfd);
二、HTTP 请求怎么构造
请求本质就是一段有格式的纯文本,用 sprintf 把城市名拼进去:
char buf[5000] = {0};
sprintf(buf,
"GET /?app=weather.today&cityNm=%s&appkey=78675&sign=xxx&format=json HTTP/1.1\r\n"
"Host: api.k780.com\r\n"
"User-Agent: Mozilla/5.0\r\n"
"Connection: keep-alive\r\n\r\n", // 末尾必须有空行 \r\n\r\n
city); // city 是全局变量,set_city() 里改
两个接口只有 app= 这个参数不一样:
- 实时天气:
app=weather.today - 生活指数:
app=weather.lifeindex
三、JSON 字段怎么提取
服务器返回的是 JSON 字符串,不用任何库,纯靠字符串函数手动抠:
// 假设 JSON 里有 "days":"2026-03-06"
char *begin = strstr(buf, "days"); // 找到 key
begin = begin + strlen("days") + 3; // +3 是跳过 ":" 三个字符(结束引号+冒号+开始引号)
char *end = strchr(begin, '"'); // 找到 value 结束的引号
size_t len = end - begin;
memcpy(days, begin, len);
days[len] = '\0';
为什么 +3? key 后面固定是
":"三个字符,跳过后指针就落在 value 的第一个字符上。
四、生活指数的多日遍历
生活指数接口返回的是数组,有好几天的数据,要循环处理:
{"result":[{第一天数据},{第二天数据},{第三天数据}]}
思路:遇到 { 记开始,遇到 } 就在这段范围内提取字段打印,遇到 ] 结束循环。
cs
char *start = strstr(buf, "result"); // 从 result 字段开始扫
char *obj_start = NULL;
while (1)
{
if (*start == '{') obj_start = start; // 新对象开始
else if (*start == '}') { // 当前对象结束,提取字段
// strstr(obj_start, "days") ...
// strstr(obj_start, "week_1") ... ← 注意是 week_1 不是 week!
printf(...);
}
if (*(start + 1) == ']') break; // 数组结束
start++;
}
close(sockfd); // 这个函数记得关
五、两个接口字段名的区别(容易搞混)
| 字段 | 实时天气接口 | 生活指数接口 |
|---|---|---|
| 星期 | week |
week_1 |
| 紫外线 | ❌ 没有 | lifeindex_uv_attr |
| 洗车 | ❌ 没有 | lifeindex_xc_attr |
| 穿衣 | ❌ 没有 | lifeindex_ct_attr |
六、踩过的坑
| 坑 | 原因 | 修复 |
|---|---|---|
typedef struct sockaddr *(SA) 编译报错 |
括号位置不对 | 改成 typedef struct sockaddr* SA |
void 函数里 return 1 报错 |
void 不能返回值 | 改成 return; |
| 生活指数 week 字段崩溃 | 字段是 week_1,用 week 找不到,strstr 返回 NULL |
改用 week_1 |
| weather 字段取出来是 weather_curr 的值 | strstr("weather") 先匹配到 weather_curr | 先提取 weather_curr,再提取 weather |
strcmp(city, "\n") 默认城市逻辑没效果 |
scanf 不读换行符,这个判断永远假 | 删掉这段逻辑 |
| 查询多次后报 too many open files | get_weather 没有 close(sockfd) |
函数末尾加 close(sockfd) |