發布時間:2024-01-24閱讀(17)
實際上,上網的大部分行為都是在進行進程間通信.. 也就是不斷地獲取信息和發送信息
比如:
1. 把服務器上面地資源數據拿到本地 (短視頻, 網頁)
2. 把本地地數據推送到服務器 (搜索, 注冊,登錄,下單)
http的底層一般是基于傳輸層協議tcp實現的

http是超文本傳輸協議, 在底層實現中涉及了很多地文本解析
再談http地無狀態: 指協議不具備記憶地能力, 不需要對于進程間通信地歷史狀態進行保存, 服務器是無法判斷用戶是否歷史上曾經打開過這個網頁了的. 也就是上一次打開網頁和這一次打開相同的網頁互相不關聯, 也不知道你上次打開過. (不會記憶)這個就叫做無狀態
request 報文

response 報文

主要請求方法解釋:

上述便是需要Content-Length的原因, 獲知正文是否存在以及正文長度

再次手寫一個便理解的簡單的HTTPServer.cc 的服務器, 使用C 完成
#include <iostream>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <strings.h>#include <signal.h>#include <string>#include <fstream> #define ERR_EXIT(m) do { std::cerr << m << std::endl; close(EXIT_FAILURE); } while(0)typedef struct sockaddr SA; int main() {signal(SIGCHLD, SIG_IGN);//信號處理, 避免子進程僵尸int listenfd, connfd, pid;socklen_t addLen;struct sockaddr_in clientAdd, serveAdd;if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {ERR_EXIT("socket");} int flag = 1; setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); //SO_REUSEADDR BOOL 允許套接口和一個已在使用中的地址捆綁(參見bind()) //SOL_SOCKET固定level設置bzero(&serveAdd, sizeof(serveAdd));//清空serveAdd.sin_family = AF_INET;//協議家族serveAdd.sin_port = htons(8080);//默認80端口serveAdd.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY == 0 作用適配地址if (bind(listenfd, (SA*)&serveAdd, sizeof(serveAdd)) == -1) {ERR_EXIT("bind");}//3: 等待隊列syn隊列的長度if (listen(listenfd, 3) == -1) {ERR_EXIT("listen");}while (1) {if ((connfd = accept(listenfd, (SA*)&clientAdd, &addLen)) == -1) {ERR_EXIT("accept");}pid = fork();//fork出來子進程if (pid) {close(connfd);//父進程關閉connfd然后僅僅進行listen. SIGCHLD會自動收尸} else {close(listenfd);//子進程進行發送響應報文char buffer[1024]; recv(connfd, buffer, sizeof(buffer), 0); std::cout << "#############################http request begin#############################################"<<std::endl; //打印recv的來自客戶端的請求并且輸出請求信息 std::cout << buffer << std::endl; std::cout << "#############################http request end#############################################"<<std::endl; std::ifstream ifs("./index.html"); if (ifs) { int len; ifs.seekg(0L, ifs.end);//定位到文件末尾 len = ifs.tellg();//獲取文件長度 ifs.seekg(0L, ifs.beg);//回到文件開頭 char *file = new char[len]; ifs.read(file, len);//讀取正文, 字符串形式讀取 ifs.close(); //開始處理響應: std::string status_line = "HTTP/1.1 200 OK
";//狀態行 std::string reply_header;//響應頭部 reply_header ="Content-Length: " std::to_string(len) "
"; std::string black = "
"; send(connfd, status_line.c_str(), status_line.size(), 0); send(connfd, reply_header.c_str(), reply_header.size(), 0); send(connfd, black.c_str(), black.size(), 0); send(connfd, file, len, 0); delete [] file; } close(connfd); exit(EXIT_SUCCESS);}}close(listenfd);return 0;}


服務器IP : 端口號 可以訪問, 服務器可能沒有開放端口, 可以在購買的服務器安全組中設置

相關視頻推薦
《tcp/ip詳解卷一》: 150行代碼拉開協議棧實現的篇章
網絡原理tcp/udp,網絡編程epoll/reactor,面試中正經“八股文”
學習地址:C/C Linux服務器開發/后臺架構師【零聲教育】-學習視頻教程-騰訊課堂
需要C/C Linux服務器架構師學習資料加qun812855908獲取(資料包括C/C ,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等),免費分享

HTTPS : 是以安全為目標的HTTP通道, 通俗說就是安全版本的HTTP,
為啥需要HTTPS
為啥叫做HTTPS , S的含義, SSL:加密,在HTTP下加入SSL層 (解決上述問題)
SSL操作步驟:
HTTPS的主要作用:一個是建立一個信息安全通道,用來保證數據傳輸的安全性,另外一個就是驗證網站的真實性了...
HTTP和HTTPS的區別如下:寫傳輸層協議之前先介紹一個四元組的概念: 網絡通信的實現就是基于四元組的,不論是TCP還是UDP 要想將數據從一端傳入到另外一端,就必須明確對端的二元組, 雙方如果都要相互通信就要確定四元組

首先我們確定要雙方不同主機上的不同進程間進行通信, 必須確定雙方的 ip port why?

上述圖主要是為了引出為啥要 ip

上述圖是為了引出為啥需要 port

報文分析

源 / 目的端口,那就是老身常談了, 從哪個進程來,到哪個進程去
32位序號和確認序號 (原諒咱留個小疑惑,后面解釋,和重傳機制有關系)
4位TCP報頭長度: 表示該TCP頭部有多少個32位bit(有多少個4字節); 所以TCP頭部最大長度是15 * 4 = 60 (基本衡量單位都是4字節為最小單位) 因為首部長度是4位 最大就是15; 所以最大首部長度就是 15 * 4 (最小單位) = 60字節
6位標志位:
16位窗口大小(先留個疑,其實就是存儲接收緩沖區還剩下的大小, 和流量控制有關)
16位校驗和: 發送端填充, CRC校驗. 接收端校驗不通過, 則認為數據有問題. 此處的檢驗和不光包含TCP首部, 也 包含TCP數據部分
6位緊急指針: 標識哪部分數據是緊急數據
tcp緩沖區概念的引入 (解釋流量控制):tcp連接建立之后是存在接收和發送內核緩沖區的....
send 還有 recv這些接口都不是直接將數據發送到網路中,也不是直接從網路中讀取數據的...
而是存在發送緩沖區和接收緩沖區的概念, 這些都是內核緩沖區。。。同樣之前的窗口大小其實就是接收緩沖區還剩余的大小, 支持流量控制 (你發送的數據不能超過,不然就滿了)

接收緩沖區大寫也對應著流量控制:why? 如何理解

接收端處理數據的速度是有限的. 如果發送端發的太快, 導致接收端的緩沖區被打滿, 這個時候如果發送端繼續發送, 就會造成丟包, 繼而引起丟包重傳等等一系列連鎖反應.
因此TCP支持根據接收端的處理能力, 來決定發送端的發送速度. 這個機制就叫做流量控制(Flow Control)
所以窗口大小就是接收端處理能力的代表 (發送端接收到窗口大小會根據窗口大小進行調節自己的發送速度,進行流量控制) 填充窗口字段就是填充的自身的接收緩沖區中剩余空間的大小 (此窗口也稱為接收窗口)
窗口大小字段越大, 說明網絡的吞吐量越高;
確認應答(ACK)機制的理解 (編序號)
ACK應答的含義就是: acknum 之前的序號的數據包我都已經收到了,下一次你從acknum開始發送吧
超時重傳機制
超時重發指的是因為網絡環境的擁堵阻塞導致了在很長一段時間發送方都沒有等到自己之前發送包的回音 (于是TCP默認是丟包)然后會采取重傳措施
由于重傳機制,會存在一些情況是 之前因為網絡擁堵的數據包 在網絡環境恢復之后正常傳入到對端, 導致對端可能會收到多份重復的數據報文,不過嘞因為序號的存在可以通過需要進行簡單的去重即可
但是這個超時時間如何確認??? 多少算合適,這個也是個置得討論的問題
TCP為了保證無論在任何環境下都能比較高性能的通信, 因此會動態計算這個最大超時時間.(抓核心主題,據網絡環境而生 超時時間)

第一種是ACK丟失

如上述情況下,滑動窗口的ACK部分丟失其實不是很緊要,因為可以通過后序的ACK確認;ACK一旦確認之后代表的含義是 默認之前的所有序列數據都已經全部收到了
情況2是數據包傳過去的時候就丟失了

單獨解釋一下 快重傳 : 就是說在接收方收到一個失序的報文段的時候就立即會發出重復確認。(目的在于使得發送方盡早地知道說自己有報文丟失了,沒有到達對面)接收方地意思就是 哥你確定你發的是對的,我前面的報文都還沒收到 (順序不對呀)三次之后發送方反應過來直接重傳,不再等待超時
擁塞控制
TCP是面向連接的,可靠的,基于字節流的傳輸層通信協議
如何保證可靠性:

性能提升上面:
1. 采取了滑動窗口
2. 快速重傳 (不需要等待超時,三次對端提醒之后自動重傳)
基于TCP應用層協議 HTTP HTTPS SSH Telnet FTP SMTP
TCP最大連接數的分析(面試常考)(從四元組的角度入手)先從報文分析入手


UDP的特征: 什么是無連接,不可靠,關鍵為什么它如此的不穩定但是在現在的短視頻 音視頻通話 DNS ARP這些全部都還使用的是UDP作為傳輸層協議
首先是無連接, 連接是什么: 連接算是一端到另外一端的不存在的一根線 (抽象的來說,這個是我的個人理解, 連接的過程也就是三次握手的過程)對于三次握手不理解的可以看我前文鏈接存在詳解
首先不論是有連接還是無連接, 我們核心應該確定的是什么? 確定四元組,對了四元組,無連接也可以進程間通信,只不過每一次必須傳入四元組, 但是口說無憑, 咱看看接口唄。對比一下:

為什么UDP是不可靠連接?
因為UDP沒有TCP的哪些為了保證可靠性的機制: 比如超時重傳機制,擁塞控制,流量控制機制,為數據包編號排序等...
思考為啥UDP如此不可靠我們還必須要使用它, 而且還會盡量的使其變得可靠, 還要專門做UDP可靠性設計,這個不是多次一舉嗎. 不如直接使用TCP?
首先解釋UDP相比TCP為什么相對實時性好, 在時間上更短, 更加快速。。。

以上是從不必要的三次握手建立連接上解釋這個速度問題, 為啥UDP更快
而且在進行數據傳輸的時候TCP還會存在一定的時間限制,時間閾值,超過這個時間就需要進行重傳, 重傳也會導致延遲性,向我們的qq聊天呀就經常出現這樣的延遲現象,很明顯底層應當是采取的TCP作為傳輸層協議.
根據上述的延遲解釋一下音視頻通話為例解釋下為啥使用UDP而不是TCP?
一句話解釋:就是通話延遲的問題,我們qq上發個消息是無所謂,延遲下我們可以等會看嘛,但是你在跟別人搞音視頻,像抖音這些,或者各種視頻,這個要是通話延遲,幾秒前說的話幾秒后出來了你這個還搞個屁呀, 還說得清嘛,這個很明顯需要實時通話,正是這樣的場景存在所以UDP必然是需要的。。。而且現在音視頻(短視頻)如此火爆更是少不了UDP了
我們再從另外一個角度來分析一下這個問題, 服務端壓力上面來考慮。。。

現有的udp可靠傳輸協議就是KCP了,感興趣的還真有必要得去深入研究一下,我個人是研究深度還不夠,先暫且淺顯的聊一聊這個UDP可靠傳輸設計的一些基本的東西,KCP要是將來我的理解深入足夠會盡力刨析一下...

首先既然提到了MTU 先解釋一下 MTU是個啥玩也.

總結UDP可靠傳輸的學習:


歡迎分享轉載→http://www.avcorse.com/read-234308.html
下一篇:絲瓜削皮嗎
Copyright ? 2024 有趣生活 All Rights Reserve吉ICP備19000289號-5 TXT地圖HTML地圖XML地圖