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;
}
?相關函數接口學習
?