一、TCP 網絡協議補充內容
1、TCP 的其他機制
? ? 1)TCP 頭部的標志位
? ? ? ? TCP 頭部可用抓包工具 (wireshark) 來查看。
頭部標志位 | 用途 |
SYN | 請求建立連接標志位 |
ACK | 響應報文標志位 |
PSH | 攜帶數據標志位,通知接收方該從緩沖區讀數據 |
FIN | 請求斷開連接標志位 |
RST | 復位標志位 |
URG | 緊急數據標志位 |
? ? ? ? TCP 各部分所占字節數:
2、機制
? ? 1)安全可靠
? ? ?(1)三次握手和四次揮手機制
(2)應答機制:TCP對于每一包數據都會給出相應的應答。發送數據時序列號表示這包數據的起始編號,響應報文中的確認號是接收方收到的最后一個字節編號+1。
? ? ?(3)超時重傳機制:當數據發送出去等待指定時間沒有收到響應,此時認為這包數據丟失則進行沖傳。
? ? ?(4)滑動窗口機制:一段緩沖區,緩存TCP已發送未收到響應,準備發送等數據
? ? 2)提高效率
? ? ?(1)延遲應答機制:發送數據的同時可以等待應答
(2)流量控制機制:結合TCP頭部的窗口大小,動態調整發送速率。
(3)捎帶應答機制:ACK報文可能和應用層的數據同時發送
3、應用示例
? ? 1)使用 TCP 協議實現全雙工聊天
? ? ? ? (1)客戶端代碼
#define SER_PORT 50000
#define SER_IP "192.168.0.144"//服務端IP地址int init_tcp_cli()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("connect error");return -1;}return sockfd;
}int main(int argc, const char *argv[])
{int sockfd = init_tcp_cli();if (sockfd < 0){return -1;}pid_t pid = fork();if (pid > 0){char buff[1024] = {0};while (1){fgets(buff, sizeof(buff), stdin);send(sockfd, buff, strlen(buff), 0);if (0 == strcmp(buff, ".quit\n")){break;}}wait(NULL);}else if (0 == pid){char buff[1024] = {0};while (1){recv(sockfd, buff, sizeof(buff), 0);if (0 == strcmp(buff, ".quit\n")){break;}printf("B--->A : %s\n", buff);}}close(sockfd);return 0;
}
? ? ? ? (2)服務端代碼
#define SER_PORT 50000
#define SER_IP "192.168.0.144"int init_tcp_ser()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("bind error");return -1;}ret = listen(sockfd, 10);if (ret < 0){perror("listen error");return -1;}return sockfd;
}int main(int argc, const char *argv[])
{int sockfd = init_tcp_ser();if (sockfd < 0){return -1;}int connfd = accept(sockfd, NULL, NULL);if (connfd < 0){perror("accept error");return -1;}pid_t pid = fork();if (pid > 0){char buff[1024] = {0};while (1){fgets(buff, sizeof(buff), stdin);send(connfd, buff, strlen(buff), 0);if (0 == strcmp(buff, ".quit\n")){break;}}wait(NULL);}else if (0 == pid){char buff[1024] = {0};while (1){memset(buff, 0, sizeof(buff));recv(connfd, buff, sizeof(buff), 0);if (0 == strcmp(buff, ".quit\n")){break;}printf("A---->B : %s\n", buff);}}close(connfd);close(sockfd);return 0;
}
? ? 2)使用 TCP 協議實現文件拷貝功能
? ? ? ? (1)客戶端代碼
#define SER_PORT 50000
#define SER_IP "192.168.0.179"int init_tcp_cli()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("connect error");return -1;}return sockfd;
}int send_file(int sockfd, const char *filename)
{int fd = open(filename, O_RDONLY);if (fd < 0){perror("open file error");return -1;}char buff[1024] = {0};while (1){ssize_t cnt = read(fd, buff, sizeof(buff));if (cnt <= 0){break;}send(sockfd, buff, cnt, 0);}close(fd);
}int main(int argc, const char *argv[])
{if (argc < 2){printf("Usage : ./a.out <sendfile>\n");return -1;}int sockfd = init_tcp_cli();if (sockfd < 0){return -1;}send_file(sockfd, argv[1]);close(sockfd);return 0;
}
? ? ? ? (2)服務端代碼
#define SER_PORT 50000
#define SER_IP "192.168.0.179"int init_tcp_ser()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("bind error");return -1;}ret = listen(sockfd, 10);if (ret < 0){perror("listen error");return -1;}return sockfd;
}int recv_file(int connfd, const char *filename)
{int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);if (fd < 0){perror("open file error");return -1;}char buff[1024] = {0};while (1){ssize_t cnt = recv(connfd, buff, sizeof(buff), 0);if (0 == cnt){printf("client off\n");break;}else if (cnt < 0){perror("recv error");break;}write(fd, buff, cnt);}close(fd);
}int main(int argc, const char *argv[])
{if (argc < 2){printf("Usage : ./a.out <recvfile>\n");return -1;}int sockfd = init_tcp_ser();if (sockfd < 0){return -1;}int connfd = accept(sockfd, NULL, NULL);if (connfd < 0){perror("accept error");return -1;}recv_file(connfd, argv[1]);close(connfd);close(sockfd);return 0;
}
二、HTTP 協議
1、萬維網 WWW
? ? 1)概念
? ? ? ? WWW 萬維網(Web):稱為世界范圍的廣域網,是一個大規模的、聯機式的信息儲藏方式。
? ? 2)解決的問題
? ???(1)萬維網服務器后臺如何標記萬維網數據 ?? ?
????????????????url : 統一資源定位符
(2)萬維網客戶端與萬維網服務器之前使用什么方式通信:
??????????????? HTTP:超文本傳輸協議
(3)萬維網客戶端如何展示請求的數據:
?????????????? ?HTML:超文本標記語言
2、url 統一資源定位符
? ? 格式:?<協議>://<主機>:<端口>/<路徑>
例如:https://www.baidu.com/?
百度主頁
3、HTTP 協議
? ? 1)概念
? ? ? ? HTTP 協議:稱為超文本傳輸協議,位于應用層。
端口:80
備用端口:8080
基于傳輸層的TCP協議
? ? 2)HTTP 通信過程
????????客戶端通信流程:
????? ? (1)請求建立TCP連接
(2)發送HTTP請求報文
(3)接收HTTP響應報文
(4)斷開連接
? ? 3)HTTP 的報文格式
? ? ? (1)報文分類
? ? ? ? HTTP 有兩類報文:
? ? ? ? 請求報文------從客戶到服務器請求報文,見圖6-12(a)
? ? ? ? 響應報文------從服務端到客戶的回答,見圖6-12(b)
? ? ? ? 由于 HTTP 是面向文本的 ( text-oriented ) ,因此在報文中的每一個字段都是一些 ASCII 碼串,因而每個字段的長度都是不確定的。
? ? ? ? (2)HTTP 請求報文的方法
方法(操作) | 意義 |
OPTION | 請求一些選項的信息 |
GET | 請求讀取由 URL 所標志的信息 |
HEAD | 請求讀取由 URL 所標志的信息的首部 |
POST | 給服務器添加信息(例如,注釋) |
PUT | 在指明的 URL 下存儲一個文檔 |
DELETE | 刪除指明的 URL 所標志的資源 |
TRACE | 用來進行環回測試的請求報文 |
CONNECT | 用于代理服務器 |
? ? ? ? (3)狀態碼
? ? ? ? ? ? ?狀態碼(Status-Code)都是三位數字的,分為5大類共33種。例如:
1xx | 表示通知信息的,如請求收到了或正在進行處理 |
2xx | 表示成功,如接受或知道了 |
3xx | 表示重定向,如要完成請求還必須采取進一步的行動 |
4xx | 表示客戶的差錯,如請求中有錯誤的語法或不能完成 |
5xx | 表示服務器的差錯,如服務器失效無法完成請求 |
????????例如,常見的三種狀態行:
? ? ? ? (4)鏈接方式
????????Connection: keep-alive ---> 長連接:連接保持一定時間
Connection: close ---> 短連接:連接立馬斷開
? ? 4)HTTP 舉例
? ? ? ? 訪問 http://news.sohu.com,得到的請求報文與響應報文。
? ? ? ? (1)HTTP 請求報文
請求報文 |
GET / HTTP/1.1\r\n Host: news.sohu.com\r\n User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Connection: keep-alive\r\n \r\n |
? ? ? ? (2)HTTP 響應報文
響應報文 |
HTTP/1.1 200 OK\r\n Date: Mon, 25 Aug 2025 06:14:56 GMT\r\n Content-Type: text/html;charset=utf-8\r\n Server: openresty\r\n Vary: Accept-Encoding\r\n Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Trace-Id: 15e6e7862abd49fdb1c327a6dbeb200d.10490.17561024969448219 Data-Source:? X-Content-Type-Options: nosniff X-XSS-Protection: 0 S-REQ-ID: 17348448226369344247 S-REQ-TYPE: 0 X-Cache-Lookup: Cache Miss Content-Encoding: gzip Cache-Control: no-cache\r\n Transfer-Encoding: chunked\r\n X-NWS-LOG-UUID: 17348448226369344247\r\n Connection: keep-alive\r\n X-Cache-Lookup: Cache Miss\r\n \r\n <!DOCTYPE html><html><head><script>if(window&&window.performance&&typeof window.performance.now==='function'){!window.MptcfePerf?window.MptcfePerf={headst:+new Date()}:window.MptcfePerf.headst=+new Date()}</script><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta http-equiv=x-dns-prefetch-control content=on><meta name |
? ? 5)使用響應報文定位網頁
#define SER_PORT 80
#define SER_IP "219.144.82.95"int create_tcp_connect()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SER_PORT);seraddr.sin_addr.s_addr = inet_addr(SER_IP);int ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){perror("connect error");return -1;}return sockfd;
}int send_http_request(int sockfd)
{char *preq = "GET / HTTP/1.1\r\n""Host: news.sohu.com\r\n""User-Agent: Mozilla/5.0(X11;Ubuntu;Linuxx86_64;rv:109.0)Gecko/20100101 Firefox/113.0\r\n""Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n""Accept-Language: en-US,en;q=0.5\r\n""Connection: close\r\n""\r\n";ssize_t cnt = send(sockfd, preq, strlen(preq), 0);if(cnt < 0){perror("send error");return -1;}return 0;
}int recv_http_respose(int sockfd)
{char buff[1024] = {0};while(1){ssize_t cnt = recv(sockfd, buff, sizeof(buff), 0);if(cnt < 0){perror("recv error");return -1;}else if(0 == cnt){printf("server off\n");break;}write(1, buff, cnt);}return 0;
}int main(void)
{int sockfd = create_tcp_connect();if(sockfd < 0){return -1;}send_http_request(sockfd);recv_http_respose(sockfd);close(sockfd);return 0;
}
?
【END】
?
?