TCP/IP协议模型:应用层:HTTP;传输层:TCP UDP;网络层:IPv4 IPv6
网络接口层
一、HTTP协议
1. 万维网
WWW(World Wide Web)
世界范围内的,联机式的信息储藏所。
万维网解决了获取互联网上的数据时需要解决的以下问题:
(1)怎样标识分布在整个互联网上的文档 URL------万维网服务端如何区分请求的数据
(2)用什么样的协议实现万维网上的各种链接 HTTP-----万维网服务端与服务器之间如何通信
(3)怎么使用户能够方便的查看文档数据 HTML(超文本标记语言) ----浏览器端如何展示请求到的万维网数据
2.URL
统一资源定位符 表示从因特网上得到的资源位置和访问这些额资源的方法。
格式:<协议>://<主机>:<端口>/<路径>
?参数
3.HTTP
HyperText Transfer Protocol 超文本传输协议
HTTP:80 ---面向文本 HTTPS:443(加密)
定义了万维网客户端如何想万维网服务器请求万维网文档,以及服务器怎样把文档传给客户端。
(1).HTTP工作过程:
1)建立TCP连接
2)客户端向服务器发送HTTP请求报文
3)服务器向客户端发送HTTP响应报文
4)释放TCP连接
(2).HTTP报文格式
请求报文(从客户端向服务器发送请求报文):请求行、消息报头、请求正文
响应报文(从服务器到客户的回答):状态行、消息报头、响应正文
HTTP是面向文本的,因此在报文中的每一个字段都是一些ASCII码串,各个字段的长度都是不确定的
(3).请求方式
GET 请求获取Request-URI所标识的资源
POST 在Request-URI所标识的资源后附加新的数据
HEAD 请求获取由Request-URI所标识的资源的响应消息报头
PUT 请求服务器存储一个资源,并用Request-URI作为其标识
DELETE 请求服务器删除Request-URI所标识的资源
TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
CONNECT 用于代理服务器
(4).状态码
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
4.JSON格式
键值对的集合
(1)键值对 “关键字”:“字符串值”
(2)对象(集合) {}
(3)对象数组 []
5.函数接口
(1).char *strstr(const char *haystack, const char *needle);
功能:在源字符串中定位目标字符串
参数: haystack:源字符串首地址
needle:目标字符串首地址
返回值:成功:定位到的目标字符串的首地址 ; 失败:NULL
(2).char *index(const char *s, int c);
功能:在一个字符串中定位一个字符
参数:s:源字符串
c:需要定位的字符
返回值:成功:返回定位到字符的地址 ; 失败:NULL
响应标头
HTTP/1.1 200 OK Date: Wed, 23 Jul 2025 07:33:59 GMT Content-Type: text/html;charset=utf-8 Server: openresty Vary: Accept-Encoding Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Trace-Id: 802100e5d5744cb6bba3fdf2ff8a6085.951.17532560398796951 Data-Source: X-Content-Type-Options: nosniff X-XSS-Protection: 0 S-REQ-ID: 159063873961547570 S-REQ-TYPE: 0 X-Cache-Lookup: Cache Miss Content-Encoding: gzip Cache-Control: no-cache Transfer-Encoding: chunked X-NWS-LOG-UUID: 159063873961547570 Connection: keep-alive X-Cache-Lookup: Cache Miss
请求标头
GET / 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,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 Cache-Control: max-age=0 Connection: keep-alive Cookie: SUV=1724151185440cesitz; gidinf=x099980109ee1956b7900e0080001b7b9f522cda0ff1; clt=1753254871; cld=20250723151431; reqtype=pc; _dfp=ZDmA0pQwxr24lgtMFaQG269FjIzJ0xyVW5vsDHNmhqo=; hideAddDesktop=true; t=1753255977242; beans_new_turn=%7B%22sohu-index%22%3A18%7D Host: news.sohu.com Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0
二、天气爬虫
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include "cJSON.h"
#include "head.h"int init_tcp_cli(const char *ip, unsigned short port)
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("fail socket");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(port);seraddr.sin_addr.s_addr = inet_addr(ip);int ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("fail connect");}return sockfd;
}int send_http_request(int sockfd, char *buf, int n)
{char vel[1024] = {0};if (n == 1){snprintf(vel, sizeof(vel),"GET ""/?app=weather.today&cityNm=%s&appkey=76834&sign=""475925eed5360335570b3bb0e264df65&format=json HTTP/1.1\r\n""Host: api.k780.com\r\n""User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ""AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 ""Safari/537.36 Edg/138.0.0.0\r\n""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\r\n""Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\r\n""Connection: close\r\n\r\n",buf);}else if (n == 2){snprintf(vel, sizeof(vel),"GET ""/?app=weather.future&cityNm=%s&&appkey=76834&sign=""475925eed5360335570b3bb0e264df65&format=json HTTP/1.1\r\n""Host: api.k780.com\r\n""User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ""AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 ""Safari/537.36 Edg/138.0.0.0\r\n""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\r\n""Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\r\n""Connection: close\r\n\r\n",buf);}// printf("Sending request:\n%s\n", vel);ssize_t size = send(sockfd, vel, strlen(vel), 0);if (size < 0){perror("fail send");return -1;}return 0;
}void parse_weather_json(const char *json_str, int type)
{cJSON *root = cJSON_Parse(json_str);if (!root){printf("JSON 解析失败!\n");}cJSON *result = cJSON_GetObjectItem(root, "result");if (!result){printf("找不到 'result' 字段!\n");cJSON_Delete(root);}// printf("%s", (char *)result->valuestring);if (type == 1){printf("\n=== 今日天气 ===\n");// cJSON *item = cJSON_GetArrayItem(result,0);// printf("%s\n",(char *)item);if (result){printf("城市: %s\n",cJSON_GetObjectItem(result, "citynm")->valuestring);printf("天气: %s\n",cJSON_GetObjectItem(result, "weather")->valuestring);printf("温度: %s°C\n",cJSON_GetObjectItem(result, "temperature")->valuestring);printf("湿度: %s%%\n",cJSON_GetObjectItem(result, "humidity")->valuestring);printf("风向: %s\n",cJSON_GetObjectItem(result, "wind")->valuestring);printf("风力: %s\n",cJSON_GetObjectItem(result, "winp")->valuestring);}}else{printf("\n=== 未来天气预报 ===\n");int i = 0;int n = cJSON_GetArraySize((const cJSON *)result);for (i = 0; i < n; ++i){cJSON *item = cJSON_GetArrayItem(result, i);printf("\n日期: %s\n",cJSON_GetObjectItem(item, "days")->valuestring);printf("天气: %s\n",cJSON_GetObjectItem(item, "weather")->valuestring);printf("温度: %s°C ~ %s°C\n",cJSON_GetObjectItem(item, "temp_low")->valuestring,cJSON_GetObjectItem(item, "temp_high")->valuestring);printf("风向: %s\n", cJSON_GetObjectItem(item, "wind")->valuestring);printf("风力: %s\n", cJSON_GetObjectItem(item, "winp")->valuestring);}}cJSON_Delete(root);
}int recv_http_response(int sockfd, int type)
{char buf[4096] = {0};char response[8192] = {0};while (1){memset(buf, 0, sizeof(buf));ssize_t size = recv(sockfd, buf, sizeof(buf) - 1, 0);if (size < 0){perror("fail recv");return -1;}else if (size == 0){break;}strcat(response, buf);}// printf("%s\n",response);char *json_start = strstr(response, "\r\n\r\n");while (*json_start != '{'){json_start++;// printf("%s\n",json_start);}parse_weather_json(json_start, type);// printf("%s\n",json_start);return 0;
}void shuru(int sockfd)
{char buf[1024] = {0};int n = 0;while (1){sockfd = init_tcp_cli("103.205.5.249", 80);memset(buf, 0, sizeof(buf));printf("请输入要查询天气的城市:\n");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';if (0 == strncmp(buf, "quit", 4)){break;}printf("请输入1或2,1对应该城市的当前天气,2对应该城市的未来天气\n");scanf("%d", &n);getchar();send_http_request(sockfd, buf, n);recv_http_response(sockfd, n);close(sockfd);}
}int main(int argc, char **argv)
{int sockfd = init_tcp_cli("103.205.5.249", 80);if (sockfd < 0){return -1;}shuru(sockfd);close(sockfd);return 0;
}
相关函数接口学习