1.????前言~🥳🎉🎉🎉
Hello, Hello~ 親愛的朋友們👋👋,這里是E綿綿呀????。
如果你喜歡這篇文章,請別吝嗇你的點贊????和收藏📖📖。如果你對我的內容感興趣,記得關注我👀👀以便不錯過每一篇精彩。
當然,如果在閱讀中發現任何問題或疑問,我非常歡迎你在評論區留言指正🗨?🗨?。讓我們共同努力,一起進步!
加油,一起CHIN UP!💪💪
🔗個人主頁:E綿綿的博客
📚所屬專欄:1.?JAVA知識點專欄
? ? ?? ?深入探索JAVA的核心概念與技術細節
2.JAVA題目練習
? ? ? ??實戰演練,鞏固JAVA編程技能
3.c語言知識點專欄
? ? ? ? 揭示c語言的底層邏輯與高級特性
4.c語言題目練習
? ? ? ? 挑戰自我,提升c語言編程能力
5.Mysql數據庫專欄
? ? ? ? 了解Mysql知識點,提升數據庫管理能力
6.html5知識點專欄
? ? ? ? 學習前端知識,更好的運用它
7.?css3知識點專欄
? ? ? ? 在學習html5的基礎上更加熟練運用前端
8.JavaScript專欄
? ? ? ? 在學習html5和css3的基礎上使我們的前端使用更高級、
9.JavaEE專欄
? ? ? ? 學習更高階的Java知識,讓你做出網站
📘 持續更新中,敬請期待????
?2.應用層協議
自定義協議?
在應用層這里, 很多時候, 都是程序員"自定義"應用層協議的,(當然,也是有一些現成的應用層協議,咋們之后講)
咱們這里的自定義協議,很簡單就能去設定一個,設定規則如下:
1.發送數據:按照我們自己設定的方式去得到信息內容 再正常去傳輸它?? ?接受數據:按照自己設定的方式處理 正常接受的數據
2.約定好信息按照什么格式來組織
信息的格式?
那么信息可以按照什么格式呢?
1.基于行文本的方式傳輸(自定義格式)
“1234|180E40N”或者“1234,180E40N”等都可以為自定義格式,我們在這字符串里面用什么樣的分隔符都是可以靈活進行選擇的,只要確保客戶端和服務器, 使用同一套規則進行通信即可。
自定義格式的可維護性比較差,當屬性多了的時候,放眼看上去一片混亂
2.基于 xml 的方式
它是一種經典的數據組織格式,下面是它的格式:<request> <userld>1234</userld> <position>180E40N</position> </request>
這里我們看到它跟html格式一樣,對于html 可以理解成一種特殊的 xml,xml 也是成對的標簽來組織的,xml 中,內部標簽的名字是啥, 標簽如何嵌套都是你可以自定義的.
這里有一個缺點:在網絡傳輸中,它會消耗額外的帶寬 (需要把 key 也進行傳輸)
3.?基于json的方式傳輸
這是當前最流行,最廣泛使用的方式,當前在網絡通信的時候經常用到 json 格式尤其是后面學到 web 開發,json 會用的非常多,而且可讀性非常好,比 xml 更簡潔
格式如下:
?{ userld: 1234, position: "180E40N" }?
用 {}作為邊界.{}里面是鍵值對
鍵值對之間使用,分割? ? ? ?鍵和值之間使用:分割.json雖然比xml更簡潔,但同樣在網絡傳輸中,它也會消耗額外的帶寬
4.基于protobuffer(pb)的方式傳輸
前面幾種都是 文本格式,肉眼能看懂,pb 則是 二進制 格式了,肉眼看不懂,也沒法手搓出一個例子出來
它針對要傳輸的數據進一步的整理和壓縮了雖然可讀性不好,能夠把空間最充分的利用,最節省網絡帶寬,效率也最高,對于傳輸效率要求高的場景 推薦用這個
?現成的協議——DNS協議
其中最典型的是http協議,之后會詳細講解,這里我們講另外的一個現成協議——DNS協議
在說DNS協議之前,我們先說DNS,DNS又叫域名解析系統,由DNS協議和DNS服務器組成
這里出現了個域名的概念:域名是什么呢?它是由于ip不易被人理解,所以我們就把ip變為易理解的域名。
一個典型的域名由多個部分組成,從右到左分別是最頂級域名、二級域名,以及可選的子域名。
例如?https://kimi.moonshot.cn/chat/cvi2du6s1rh9tkh0jkpg?是一個網址,其中域名是
kimi.moonshot.cn
具體來說:
頂級域名:
.cn
(中國國家頂級域名)二級域名:
moonshot
(主域名)子域名:
kimi
(子域名,用于進一步區分不同的服務或站點)
那么DNS作用是什么呢?
在域名解析過程中,客戶端(如用戶的計算機)會向DNS服務器發送一個基于DNS協議的請求,請求中包含需要解析的域名。DNS服務器收到請求后,會根據其記錄查找對應的IP地址,并按照DNS協議的格式返回給客戶端。
上述是DNS的作用,由DNS協議和DNS服務器一起完成,那么對于其內部的組成DNS協議和DNS服務器的作用分別是什么?
DNS協議:是域名解析服務所遵循的規則和標準,定義了如何進行域名與IP地址的轉換,以及如何在不同的網絡設備之間傳遞解析請求和響應。
DNS服務器:是實際存儲域名與IP地址映射關系的計算機或設備,它依據DNS協議來響應客戶端的解析請求。
因此,域名解析系統是DNS協議和DNS服務器共同構成的一個完整體系,缺一不可。
那么這里有一個問題:全世界,無時不刻都有很多設備需要進行 DNS 的請求, 這一組 DNS 服務器,能抗住這么高的請求量嘛??
肯定是不能的,所以我們通過兩個方法去解決:
1.開源
搭建DNS系統的大佬們,就開始號召各個網絡運營商,你們都可以自己搭建一組"DNS 鏡像服務器",鏡像服務器的數據,都從他們這邊來實時同步,此時用戶就會優先訪問離自己最近的鏡像服務器,這樣就減少源服務器的請求量。
2.節流,讓請求量變少,讓每個上網的設備,搞本地緩存
我的電腦 1min 之內要訪問 10 次 www.sogou.com,但只需要第一次請求 DNS 即可,把請求得到的結果ip保存到本地,后面9 次請求都使用第一次的結果即可,這樣就減少了請求量。(域名的變換,沒有那么頻繁)?
這就是DNS協議的具體講解,對于應用層的其他具體現成協議我們會在之后單開一個文章講解。?
3.傳輸層協議?
傳輸層協議分為udp和tcp,之前已經講過它們的區別,這里深入講下它們的結構,由于tcp比udp復雜的多,我們先講udp。
UDP
UDP的傳輸形式是基于數據報的,UDP數據報分為UDP 報頭和UDP 載荷(完整的應用層數據報)
下面我們根據這udp數據報的結構去深入探究udp:
UDP首部有8個字節,由4個字段構成,每個字段都是兩個字節,
由于傳輸層跟端口密切相關,所以這里理應存在目的端口號和源端口號,都為兩個字節。
UDP長度描述了整個UDP數據報占多少個字節,由于udp長度存儲單位為兩個字節,預估整個udp數據報大小為64kb(這里我們也可以看出UDP的一個弊端,在當今社會,64kb實在太小了,而由于一些原因,UDP所攜帶的數據大小無法改變,如果有大數據要通過udp傳輸就需要拆包和合包,tcp就沒這個煩惱,無大小限制)
前提: 網絡傳輸中,由于一些外部干擾,就可能會出現數據傳輸出錯的情況,
光信號/電信號磁場,電場, 高能離子.. 某個地方本來是傳輸低電平, 在干擾下就成了高電平了,比特翻轉,所以數據發生變化。
因此,就需要有辦法,能夠識別出出錯的數據.校驗和就是這樣的一種檢查手段校驗和:檢測UDP數據報在傳輸中是否發生改變,改變了則傳輸過來的數據包則丟棄且重傳。
校驗和其實本質上是一個字符串,體積比原始的數據更小, 通過原始的數據用特定算法生成。原始數據相同,得到的校驗和就一定相同.反之,校驗和相同,原始數據大概率相同 (理論上會存在不同的情況, 實際的概率非常低,可以忽略不計),校驗和不同則原始數據一定不同。
如何基于校驗和來完成數據校驗呢?
1.發送方,把要發送的數據整理好(稱為 data1),通過一定的算法,計算出校驗和 checksum1
2.發送方把data1 和 checksum1 整合為數據報一起通過網絡發送出去.
3.接收方收到數據, 收到的數據稱為 data2(數據可能和 data1 就不一樣了),?接收方再根據 data2 重新計算校驗和 (按照相同的算法),得到 checksum2
4.對比 checksum1 和 checksum2 是否相同. 如果不同,則認為 data2 和 data1 一定不相同.
如果 checksum1 和 checksum2 相同,則認為 data1 和 data2 是相同的(理論上存在不同的可能性,概率比較低,工程上忽略不計)?
計算校驗和,有很多種算法:
此處 UDP 中使用的是 CRC 算法(循環冗余算法)
把當前要計算校驗和的數據,每個字節,都進行累加,把結果保存到這個兩個字節的變量中,如果中間某個數據, 出現傳輸錯誤, 第二次計算的校驗和就會和第一次不同
CRC 這個算法其實不是特別的靠譜,導致兩個不同的數據,得到相同的 crc 校驗和的概率比較大.(前一個字節恰好少1,后一個字節恰好多1),這里的概率大是相較于其他算法的概率比的,在正常應用中還是可以忽略不計這個誤差的。
除了該算法,還有md5/sha1 算法 (這里我們就只介紹 md5)
這里有一系列的公式,來完成 md5 的計算,(咱們不需要考慮公式是啥樣的,是一個數學問題),但是咱們需要知道 md5 的特點:
1.定長:無論你原始數據多長, 計算得到的校驗和都是固定長度,校驗和本身就不應該很長,要不然不方便網絡傳輸
2.分散:給定兩個原始數據,哪怕絕大部分內容都一樣,只要其中1個字節不同,得到的校驗和值都會差異很大.?3.不可逆:給你一個原始數據,計算 md5非常容易.給你 md5還原出原始數據, 計算量非常龐大,以至于超出了現有計算機的算力極限,理論上是不可行的(所以md5 也可以應用在一些密碼學場景中)
md5 在工作中非常常用,大家一定要熟悉這幾個基本特點.?
相比于 UDP 來說,TCP 在更多的情況下是具有優勢的,很多時候我們都是優先考慮使用 TCP,它也更復雜,接下來我們來講解一下tcp。
TCP?
我們同樣根據這tcp數據報的結構去深入探究tcp:
其數據部分稱為載荷,數據部分之外的稱為報頭。由于TCP是可靠傳輸,所以報頭部分相比udp會格外復雜。
16位源/目的端口號:跟udp一樣
32位序號/32位確認號:后面會詳細講到
4位TCP報頭長度:表示該TCP報頭的長度,其長度是可變的,不跟udp一樣(長度為20—60字節)
保留(6位):未來某天TCP需要擴展一些新功能,就可以使用這個保留位來表示,暫時還沒有用到
?6位標志位:之后內容會講到16位窗口大小:后面會詳細講到
16位校驗和:跟udp的校驗和一摸一樣,這里不再敘述了
16位緊急指針:標識哪部分數據是緊急數據(用的不多,不會詳細說明)
選項:可理解為是可選項,可以選擇加還是不加(這塊可有可無就對TCP的報頭產生影響),如果選項完全沒有,tcp報頭長度就是20個字節,如果選項拉滿,tcp報頭最長是60個字節。報頭最大長度是60,去掉固定的20,剩下選項部分最多40個字節。
?TCP的10個核心機制
在剛才對tcp的數據報研究中,我們發現了很多udp不存在的結構,而這些結構都是跟我們TCP的核心機制有關,核心機制總共有10個,下面我們一個一個講解這些機制并附帶說明這些多出來的結構。?
TCP有一個最核心的特性:可靠傳輸, 它是 TCP 最最核心的特性?
可靠傳輸,不是說,發送方把數據能夠 100% 的傳輸給接收方(要求太高了)
而是發送方發出去數據之后,能夠知道接收方是否收到數據,一旦發現對方沒收到,就可以通過一系列的手段來補救重新去發送。
確認應答機制?
確認應答機制是保證TCP可靠傳輸的一個核心機制。
確認應答機制:發送方把數據發給接收方之后,接收方收到數據就會給發送方返回一個應答報文(ack報文),發送方如果收到這個應答報文了,就知道自己的數據是否發送成功了(應答報文是什么我下面會解釋)
?
單看這一幅圖我們知道一般數據在TCP的傳輸通常都是一個接著一個,只有確認了一個數據傳輸成功才會傳送下一個數據。
但這里還有個疑問:為什么會有數字的出現?
其實這數字指的就是序號和確認序號。
在網絡傳輸過程中,會出現一種情況,叫做"后發先至",也就是后發的消息反而先到,先發的消息反而后到,所以我們就不能根據到達順序去將ack報文和數據報進行一一對應。
所以我們就引入序號和確認序號來將ack報文和數據報進行一一對應。
(對于這種數據一個個傳輸的其實并不存在后發先至,因為一次傳輸它就一個數據,后發先至情況一般都出現在滑動窗口機制中,那個機制是一次傳輸很多數據,之后會詳細講到)
注意:后發先至是網絡通信中客觀存在的,改變不了。
我們引入一個序號和確認序號。只要能夠對傳輸數據進行編號,并且讓應答報文的編號和發送數據的編號,能夠一一對應,即使出現后發先至,也不影響對于傳輸意思的理解
在上述的32位序號和32位確認序號,此時32位序號就是發送數據的序號,32位確認序號就是給應答報文用到,這樣的數據就可以根據確認序號區分出要應答哪個上面的數據了。?
假設一個TCP 數據包里一共有 1000 個字節的載荷數據.其中第一個字節的序號是 1,就在 TCP數據報的序號字段中寫1.
由于一共是 1000 個字節,此時最后一個字節的序號自然就是1000 了.但是 1000 這樣的數據并不需要在 TCP 報頭中記錄。因為剩下其他字節的序號,都可以依次的推出,所以只需要寫第一個(雖然 tcp 序號是連續遞增,但不一定是從 0 或者1開始的,具體從哪里開始,為啥這么設定,后面"連接管理"再詳細解釋)
確認序號設定也非常有特點,確認序號取值就是要在應答的數據的最后一個字節的序號再 +1,所以依照上面的假設,在應答報文中, 就會在確認序號字段中填寫 1001,這樣就表示1001 之前的數據, 都被 B 收到了。
那么說了這么久,如何區分應答報文(ACK報文)和正常的數據報呢?
這就到了我們所說的標志位中的ACK:
這一位為 1,表示當前數據包是一個應答報文.此時數據包中的"確認序號字段"就生效.
這一位為 0,表示當前數據包是一個普通報文.此時數據包中的"序號字段"就生效.?此外應答報文中沒有載荷,正常數據報里有。
所以我們通過特殊的 ack 數據包里面攜帶的"確認序號"就能告訴發送方,哪些數據已經被確認收到了。此時發送方就心中有數了,就知道了自己剛發的數據是到了還是沒到,這就是可靠傳輸。
TCP 的初心是為了實現可靠傳輸 ,達成可靠傳輸的最核心的機制就是確認應答機制?
所以這里有個面試題:
TCP 是如何保證可靠傳輸的??
正確答案:通過確認應答為核心,借助其他機制輔助最終完成可靠傳輸
錯誤答案:三次握手/四次揮手保證了可靠傳輸.?(這個是錯誤的,它們只是為可靠運輸提供了基礎和保障,算是輔助機制,不是核心機制)
超時重傳機制?
TCP最核心的功能就是可靠傳輸,可靠傳輸之所以能達成,主要是依靠"確認應答"機制,這里是通過應答報文來通知發送方,我已經收到請求,這是一切順利的情況,如果不順利呢?假如出現"丟包"呢??
丟包是指數據在傳輸過程中,被丟棄,無法到達對端,也是客觀存在的隨機事件。
那為什么會出現丟包,是因為在網絡傳輸過程中,里面錯綜復雜,A給B傳輸數據,會經過多個路由器和交換機,這些路由器交換機又不止是給A和B提供數據傳輸服務,整個網絡是非常繁忙的。若其中一個路由器/交換機過于繁忙,需要處理的數據量超過極限,那么就會把多出的部分直接丟棄,這就丟包了。
那么就引入了超時重傳機制,就是用來應對網絡出現丟包的情況,針對確認應答機制,進行補充。正常情況下,TCP就是通過確認應答來知道數據是否被對端收到了。假如A給B傳輸數據,若過程中出現丟包了,那么B不會收到A發來的數據,此時B也不可能給出任何應答。A就可以根據"是否收到了ACK"來區分是否出現丟包。
當A從發送數據之后,到正常收到ACK,在這中間肯定也需要一定的時間,A就會進行等待,如果等待時間超過了某個閾值,還沒有收到ACK,此時就可以認為出現丟包了,此時就會觸發重傳。
那么主機A沒有收到ACK有兩種情況:
主機A發送數據給B之后,可能因為網絡擁堵等原因,數據無法到達主機B(數據丟了)
主機B收到主機A的數據之后,做出應答后,應答報文沒有到達主機A(ack丟了)
這兩種情況客戶端都會進行重傳數據
站在主機A的角度,A是無法區分是數據丟了,還是ACK丟了,A能看到的都是沒有收到ACK。A做的事情就是觸發重傳。
但是呢,對于情況一,重傳數據就好,但是如果出現第二種情況,那么這些數據不是相同了嗎,不就出現數據重復了嗎?很明顯,這是不科學的。
TCP接收方,會針對收到的數據進行去重,會按照序號來進行去重,下面講講去重的內部機制。
接受緩存區?
TCP傳輸層內部有一個接受緩沖區。當數據從網絡層傳遞到傳輸層時,TCP會將數據存入接收緩沖區,直到應用程序通過系統調用(如
receive
或read
)讀取這些數據。對于這個接受緩沖區,如果在這內部有一個數據報,再傳輸進來一個序號相同的數據報,那么接受緩沖區是不會接收該數據報,所以就達成了一個去重的效果,很好的避免了數據重復,這里的判斷數據報是否相同是根據數據報中的序號去判斷的,而不是載荷中的數據
接受緩沖區,除了去重之外,還有一個很重要的功能,就是針對收到的數據進行排序
因為網絡傳輸可能會后發先至,所以導致數據接受的順序就跟我們開始發送時不一樣,我們肯定希望咱們發出去的數據能夠有序的到達接收方,有序的被處理。
所以在接收緩沖區里就會對收到的數據先排個序,讓序號小的在前頭,序號大的在后頭,并且數據和數據之間的序號始終都是連續的,這樣就跟初始發送時的順序一樣。?
(正常的一個一個傳輸是不需要再進行排序,因為不存在后發先至,所以接受順序是跟發送順序一摸一樣,滑動窗口的傳輸因為存在后發先至,所以要用到接受緩沖區里的排序)
講完上述這些,我們又會想超時的時間如何確定?
這個時間的長短,隨著網絡環境的不同,是有差異的。
如果超時時間設的太長,會影響整體的重傳效率;
如果超時時間設的太短,有可能會頻繁發送重復的包;
TCP為了保證無論在任何環境下都能比較高性能的通信,因此會動態計算這個最大超時時間Linux和Windows 超時都以500ms為一個單位進行控制,每次判定超時重發的超時時間都是500ms的整數倍。
如果重發一次之后,仍然得不到應答,等待 2*500ms 后再進行重傳。如果仍然得不到應答,等待 4*500ms 進行重傳。依次類推,以指數形式遞增。
當累計到一定的重傳次數(如Linux中的tcp_retries2
參數,默認為15次),系統會發送帶有RST標志位的重置報文來清空中斷狀態并立即請求主動終止雙方的連接。如果RST報文傳輸過去接受方還沒響應,系統會認為網絡或對端主機出現異常,從而強制關閉連接(總而言之就是當累積次數過多時,雙方就會斷開連接,不再進行數據傳輸。)? ??
連接管理機制
連接管理機制包含建立連接 + 斷開連接
之前講過建立連接和斷開連接都是通過操作系統內核完成的,現在來說下是怎么完成的?建立連接通過三次握手完成,斷開連接通過四次揮手完成
tcp 這里的握手揮手 其實是給對方傳輸一個簡短的,沒有業務數據的數據包,通過這個數據包實現一些操作。完成這些操作后雙方就會建立連接或者斷開連接握手揮手這種操作,不是 TCP 獨有的,甚至不是網絡通信獨有的.計算機中的很多操作,都會涉及到"握手"這種操作。
下面我們分別詳細講述一下三次握手和四次揮手
?三次握手(建立連接)
建立連接就是通信雙方各自保存對端的信息,具體完成過程需要經過三次握手。三次握手其實就是客戶端服務器三次通信的過程。
三次握手的第一次,一定是客戶端先發起的(客戶端通過代碼去發起建立連接請求,從而在內部開始三次握手)這個數據報不攜帶任何業務數據,也就是載荷部分是空著的,只有TCP報頭部分,這個TCP報頭中,其中6個標志位的SYN這一位為1(意味著它就是發起請求的數據報,叫做"同步報文")
這個SYN也就是synchronize,譯為"同步",在多線程中的"同步"代表互斥,在TCP中的"同步"則是希望服務器和客戶端之間,達成某種配合關系,達成某種有關聯的狀態。
當客戶端給服務器發送SYN(我想和你建立連接),此時服務器就會給客戶端回應一個應答報文(ACK),這個應答報文也只是告訴客戶端說,我收到你的請求了,這個時候緊接著服務器就會給客戶端發起一個同步報文。?
當客戶端收到服務器發來的請求之后,也會返回一個應答報文。?
上述流程,客戶端和服務器各自給對方發送SYN,在各自給對方返回一個ACK,那么我們發現,這里面有四次交互,我們不是說三次交互嗎?其實中間這兩次是可以合并成一次的(提升效率),都是服務器給客戶端返回的數據,所以ACK和SYN可以合并成一個網絡數據。
在六個標志位中,ACK第二位為1,SYN第五位為1,所謂合并就是讓這一個TCP數據報,報頭中同時把這兩個bit位都設置為1.
所以這樣就變成了三次握手(三次信息通信),?上述就是三次握手的基本流程
那么三次握手有什么作用呢?
1.驗證雙方的接聽發送能力是否正常
通過這三次握手的信息交流,確認服務器和客戶端的發送能力和接受能力都是正常的,從而為TCP的可靠傳輸做了保障(如果這接受或者發送能力不正常的話,那么還怎么達成可靠傳輸)
所以設想一下,三次握手變成了兩次握手是否可行?那當然是不行的,此時服務器這邊對于"發送能力""接收能力"是不確定的,所以需要第三次交互,確認服務器的發送能力和接受能力。
2.確認通信路徑是暢通的
在正式傳輸業務數據之前,我們可以用報文去確認一下通信鏈路是否暢通,以便后續的傳輸
3.協商一些必要的參數
有些參數不是單方面就能確認,需要雙方共同來確認出來。要協商的東西有很多,其中TCP通信時使用的序號,就是協商出來的(通常不是0/1)
所以在三次握手后,我們完成了這些操作(以上三個作用),客戶端和服務器的連接也就隨之建立好了。
四次揮手(斷開連接)
對于三次握手,第一次發送請求一定是客戶端第一次發起,而四次揮手,客戶端和服務器都可以主動發起!
那么怎么主動發起呢?當我們在代碼中對socket對象調用close或者直接結束該進程的時候,它就會主動發起第一次請求。
此處以客戶端主動提起為例:
當前客戶端要進行斷開連接,什么時候會觸發斷開連接,當客戶端代碼調用 socket.close 或者客戶端進程結束,這樣的情況就會觸發tcp的四次揮手。
一旦close或者結束進程,客戶端就會給服務器發起一個FIN(結束報文)數據報,FIN就是TCP中的一個標志位,代表著希望結束這段連接,服務器收到后立即返回ACK,返回應答報文之后,服務器就會給客戶端發起FIN報文(這里的發送也是應用端層面的發送,屬于我們所控制的,下面會說),接受成功后客戶端返回ACK,最終完成斷開連接的過程。
TCP中期望達成的效果是雙方互刪,所以雙方都要發送FIN。
那么這里的四次揮手中間兩次交互是否可以合并??
三次握手過程中,服務器收到客戶端發來的請求后,SYN 和 ACK都是內核自動控制發送的返回,返回的時機其實都是內核控制的,同一時機。
而四次揮手,當服務器收到客戶端發來的FIN(假設客戶端主動提出斷開連接),此時服務器就會立即返回ACK,這也是由內核控制的,當我們在代碼中調用close或者直接結束進程的時候,才會觸發服務器給客戶端發送FIN(應用程序控制的)。這兩個操作不是同一時機,中間可能會隔很久。
所以通常情況下是不能合并的,一個是內核立即發送,一個是我們決定什么時候發送。
但是這是通常情況,在特殊情況中TCP里面有一個延時應答機制可以讓它們一起發送,該機制可以讓ACK在FIN發送時才跟著一起返回出去,從而合并到一塊,"延時應答"機制后面會詳細講述。
上述的合并情況,屬于"特殊"情況,對一般情況是不能合并的,所以,最終還是把斷開連接稱為"四次揮手"。
那么這里有個疑問,假設客戶端發起了請求,服務器做出了ACK回答,但是服務器接下來一直沒close或者結束進程,難道要一直等它發FIN嗎?
?這是不可能的,這里要說一個重要的狀態:CLOSE_WAIT
它是第一次接受FIN報文到第二次自己發送FIN報文的時間,如果這里CLOSE_WAIT時間過長,一直都沒有發送FIN的話,那么系統就會直接強制斷開雙方的連接,對于強制斷開連接的話,其實是沒什么bug的,但肯定沒主動斷開連接好。
注意:當代碼中調用close并不會開始就執行,而是會先發送一個fin包從而開始執行任務(第二次調用也是同理),只有完成這四次揮手,雙方的close才會相繼執行(先請求斷開的close后執行,對端先執行),執行完后通信雙方就會刪除對端信息(斷開連接)。
除此以外,這里還有一個狀態:TIME_WAIT?
TIME_WAIT是第二次接受FIN到自己closed的期間時間,那么我們不可以接收到FIN就直接close嗎,還非要等一會,TIME_WAIT存在的意義是什么?
TIME WAIT存在的意義,就是為了應對最后一個 ACK 丟包。客戶端在收到服務器返回的 fin 之后,不能立即釋放 tcp 連接(close),如果立即釋放了,后續一旦對端重傳了 fin(ack丟包了),此時就因為過早釋放TCP連接無法返回 ack 了
因此客戶端這邊就需要有一個特殊的狀態 TIME WAIT 狀態來等待可能到達的 fin 重傳的數據。所以只有當對面成功接收到ACK,成功close了之后,我們客戶端才能緊跟著close,不然就處于TIME WAIT,同樣TIME WAIT 狀態不是持續的,而是有一定時間的,超出了時間,如果還沒closed結束掉,就會強制斷開雙方的連接,跟CLOSE_WAIT一樣,不會產生很嚴重的后果,但肯定沒主動斷開連接好。
這兩個狀態等待的時間都是2MSL,MSL是什么,網絡上兩個節點通信消耗的最大時間為 MSL,等待時間為其兩倍,如果還沒接收到,說明沒救了,就強制斷開。?
那么四次揮手有什么作用呢?
四次揮手的設計確保了 TCP 連接的關閉過程是可靠的、有序的,并且能夠避免數據丟失、資源泄漏和連接狀態混亂等問題,保障了TCP的可靠性。
滑動窗口機制?
前面我們講到的確認應答,超時重傳,連接管理都是用來保證TCP可靠傳輸的機制。
而滑動窗口機制則是用來提高TCP效率的機制。
我們知道對每一個發送的數據報,都要給一個ACK確認應答。收到ACK后再發送下一個數據段。這樣做有一個比較大的缺點,就是效率較低,尤其是數據往返的時間較長的時候,跟udp效率簡直沒法比
所以我們要針對TCP盡可能的提高效率,將它與udp的效率差距盡可能縮小。TCP 只要引入了可靠性,傳輸效率是不可能超過沒有可靠性的 UDP。
這就引出來了滑動窗口機制:?
那我們就想,既然這樣一發一收的方式性能較低,那么我們一次發送多條數據,就可以大大的提高性能。
滑動窗口便是如此
那么下面我們來詳細說下滑動窗口,以上圖為例:
該機制最開始會同時發送多條數據,數據量由窗口大小表示:上圖的窗口大小就是4000,所以可以最開始同時發送4000的數據量
在發送完初始的數據量后,后續的數據怎么發送呢?
只有當主機A收到序號最小的數據包(1-1000)返回的ACK后,才會繼續發送第五個字段(4001-5000)的數據,發送完4001-5000后,才能繼續發送5001-6000的數據,同理該數據要收到1001-2000數據包返回的ACK后,才能發送出去。以此類推按順序執行。
這里看起來的直觀效果,這個"窗口"就開始往后"滑動”,就叫滑動窗口機制。
那么這過程中出現了丟包怎么辦?分為兩種情況:
情況一:數據包已經抵達,ACK被丟了
發送的數據包已經抵達,回應報文ACK卻丟了這種情況下,部分ACK丟了并不要緊,因為可以通過后續的ACK進行確認;
這是因為ACK應答報文上的確認序列號表示的是,該字節序以前的報文一全部到達,請下一條報文從該字節序開始。
就比如上圖中的1001丟了,但是收到了2001,也就代表2000以前的數據已經全部收到了。所以此時是否收到1001已經無所謂了
情況二:數據包直接丟了
比如上述情況,1001-2000的數據包丟了
當1001-2000報文段丟失之后,雖然主機A一直在給主機B往后發送數據,但是接收端一直沒有收到1001這段的數據報,就會一直向發送端索要1001的數據
發送端發現連續三次收到了接收端發來同樣一個 “1001” 這樣的應答,他就明白了這段數據丟了,就會將對應的數據 1001 -2000 重新發送,這個就叫快速重傳
快速重傳機制:當發送方連續收到三次相同的失序確認應答(ACK)時,就會認為對應的數據包丟失,并立即進行重傳,而不需要等待超時事件發生。這種機制可以快速補發丟失的數據包,提高傳輸效率
這個時候接收端收到了 1001 之后,再次返回的ACK就是7001了(因為2001 - 7000接收端其實之前就已經收到了)
所以這就是區別于普通傳輸情況的滑動窗口傳輸機制。
如果通信雙方,傳輸數據的量比較小,也不頻繁, 就仍然是普通的確認應答,按照普通的超時重傳處理重傳。
如果通信雙方, 傳輸數據量更大,也比較頻繁, 就會進入到滑動窗口模式, 按照快速重傳的方式處理重傳.
流量控制機制?
接收端處理數據的速度是有限的。如果發送端發的太快,導致接收端的緩沖區被打滿,這個時候如果發送端繼續發送,就會造成丟包,繼而引起丟包重傳等等一系列連鎖反應。
因此TCP支持根據接收端的處理能力,來決定發送端的發送速度。這個機制就叫做流量控制
具體如何衡量接收方的處理能力呢?
直接通過接收方的接收緩沖區的剩余空間大小,作為衡量處理能力的指標
剩余空間越大,意味著消費速度越快,處理能力就越強.
剩余空間越小,消費速度越慢,處理能力就越弱.
那么接收端的處理能力怎么返回告訴發送端呢?
接收方每次收到數據之后,都會把接收緩沖區剩余空間大小通過 ack 返回給發送方.發送方就會按照這個數值來調整下一輪的發送速度。
那么緩沖區剩余空間大小在TCP中是什么形式表示的呢?
TCP中的16位窗口大小就是去描述接收緩沖區剩余空間大小
所以接收端將接收區緩沖區剩余空間大小放入 TCP 首部中的 “窗口大小” 字段,通過ACK端通知發送端;
如果窗口大小比較大,則發送方速度就比較快,如果窗口大小較小,則發送方速度就比較慢
如果接收端緩沖區滿了,就會將窗口置為0,這時發送方不再發送數據,此時發送方會定期發送一個窗口探測數據段(不攜帶載荷),從而觸發ACK,知道B這邊的緩沖情況,接收端把窗口大小告訴發送端,如果此時窗口大小不為0,則會繼續發送。
由于窗口大小是16位?,所以接收緩沖區剩余空間大小是不是只能最多為64k?
其實TCP 報頭中,選項部分里有一項是叫做"窗口擴展因子",通過擴展因子, 就可以讓窗口大小表示一個更大的值,不是最多只能64k。
擁塞控制機制?
擁塞控制和流量控制類似,流量控制是站在接收方的角度從而影響發送方的速度。但是呢,發送方發得有多快,不光要考慮接收方的接收能力,還要考慮中間的路由器/交換機是否能接受,中間這些機器的處理能力是不確定的,鏈路上的任何一個節點,性能瓶頸都會制約發送方的發送速度。
所以流量控制是基于接收方的處理能力去控制,而擁塞控制是基于通信過程中中間節點的處理能力去控制的。
同樣擁塞控制機制中也跟流量控制機制一樣,存在一個窗口,叫擁塞窗口,它是TCP協議中用于控制網絡擁塞的一個重要參數。用于動態調整發送方發送數據的速率,以避免網絡擁塞。擁塞窗口的大小會根據網絡的狀況動態調整,以優化數據傳輸效率。那么擁塞窗口的值怎么調整的呢?
流量控制的時候,很容易定量的來衡量其窗口大小(通過緩沖區的剩余大小)。但是在擁塞控制機制中衡量窗口值就比較復雜,因為通信過程中節點里有多少設備?每次走的路徑可能都不一樣,每個設備的處理能力,繁忙程度都不一樣,這樣就很難衡量出來
所以我們就不管你中間結構有多復雜,tcp都把他們視為一個整體,然后通過"實驗"的方式,去調整擁塞窗口的大小:
慢啟動階段(Slow Start):
在TCP連接建立或重新啟動時,擁塞窗口的初始值通常設置為1個最大報文段(MSS)。
每當發送方接收到一個確認(ACK),擁塞窗口的大小會按指數級增長(翻倍)。
這種增長方式會持續到擁塞窗口達到一個預設的閾值或檢測到網絡擁塞。
擁塞避免階段(Congestion Avoidance):
當擁塞窗口達到閾值時,進入擁塞避免階段。
在此階段,擁塞窗口的增長變為線性增長,每次收到一個ACK時,窗口大小增加一個較小的固定值。
這種方式旨在避免網絡過載,同時盡可能利用網絡帶寬。
網絡反饋機制:
TCP通過觀察網絡的反饋(如往返時間RTT、丟包率等)來判斷網絡擁塞狀態。
動態調整:
當檢測到數據包丟失(如通過超時或重復ACK),TCP會認為網絡發生擁塞,將擁塞窗口減小到初始值,并重新進入慢啟動階段
通過這些機制,TCP能夠動態調整擁塞窗口的大小,以適應網絡的實時狀態,從而在避免擁塞的同時最大化傳輸效率。
因為流量控制,擁塞控制都是在限制發送方的的發送速度。
所以最終時機發送的窗口大小,是取 流量控制 和 擁塞控制 中的窗口的較小值,(必須讓接收方和網絡的中間結點都可以接受,所以必須取較小值,較大值會有一方接受不了)
延遲應答機制?
一般情況下,A 把數據傳給 B, B 就會立即返回 ack 給 A
也有的時候, A 傳輸給 B, 此時 B 等一會再返回 ack 給 A,這個就叫延遲應答機制那么這么干有什么作用呢?
延時返回 ack,給接收方更多的時間,來讀取接收緩沖區的數據,此時接收方讀了這個數據之后,緩沖區剩余空間變大了,返回的窗口大小也就更大了,這就提升了傳輸效率
捎帶應答機制
捎帶應答機制允許在數據傳輸的過程中,將確認應答信息“捎帶”在數據包中一起發送,而不是單獨發送一個ACK包。這種機制建立在延時應答的基礎上,通過將原本需要單獨發送的確認應答(ACK)報文與其他數據包合并,從而減少網絡中的確認消息數量,提高網絡利用率。
更準確的說,四次揮手可以三次揮完,就是捎帶應答的體現,該機制能使四次揮手變為三次揮手。
網絡通信中,往往是這種"一問一答"這樣通信模型。
ack 是內核立即返回的,response 則是應用程序代碼來返回的,這兩者時機是不同的.
由于 tcp 引入了延時應答, 上面的 ack不一定是立即返回, 可能要等一會,在等一會的過程中,B 就正好把 response 給計算好了,計算好了之后就會把 response 返回,于此同時順便就把剛才要返回的 ack 也帶上了,這兩個數據就合并成了一個數據,提升了效率。
面向字節流的粘包問題機制?
此處"包"指的是應用層數據包. 如果同時有多個應用層數據包被傳輸過去,此時就容易出現粘包問題
目前,接收緩沖區中,這三個應用層數據包的數據,就是以字節的形式緊緊挨在一起的.接收方的應用程序, 讀取數據的時候,可以一次讀一個字節,也可以讀兩個字節,也可以讀 N 個字節
但是最終的目標是為了得到完整的應用層數據包
B 應用程序, 就不知道,緩沖區里的數據,從哪里到哪里是一個 完整 的應用數據包了
相比之下,像 UDP 這樣的面對數據報的通信方式,就沒有上述問題
UDP 的接收緩沖區中,相當于是一個一個的 DatagramPacket 對象
應用程序讀的時候,就能明確知道哪里到哪里是一個完整的數據?
那么該怎么解決該問題呢?
- 使用分隔符(在之前的服務器代碼中,我們通過scanner中帶有的機制,只要讀到空白符就結束了,所以我們使用空白符來作為分隔符)
- 約定包的長度,可以在包頭的位置,約定一個包總長度的字段,從而就知道了包的結束位置
對于字節流的粘包問題,不是只有tcp才會有,只要是面向字節流的對象,都會有粘包問題?
對于自定義的數據格式我們要按照上述的規則自己去解決粘包問題。
而像xml,json, protobuffer這些定義好了的數據格式,本身都是明確了包的邊界的?
json, xml, yml 都屬于是基于分隔符的方式來進行區分的,protobuffer 按照 長度的方式來區分
保活機制?
假設出現主機掉電,網線斷開的情況:
此時是一瞬間的事情,來不及斷開進程,也來不及發送 FIN請求,主機直接就停機了,站在對端的角度,對端都不清楚對方停機了,所以連接還一直保持著,不會斷開,那么之后會發生什么情況呢?
這時候就到我們的保活機制出現用處的時候了。?
當TCP連接處于空閑狀態(即沒有數據傳輸)一定時間后(默認通常是2小時),保活機制被觸發。
由一方(通常是客戶端或服務器端,具體取決于實現)發送一個特殊的探測報文(可以類比為"心跳包”),這個報文是一個不攜帶業務數據的TCP報文段,通常是一個帶有ACK標志位的報文段。
如果對方正常響應(返回一個ACK報文段),則認為連接仍然有效,保活計時器重新開始計時。如果對方沒有響應,發送方會重復發送探測報文多次(通常默認是3次,間隔時間通常默認是30秒),如果多次探測后仍然沒有收到對方的響應,發送方就認為對方已經“掛了",并主動關閉連接。
所以根據保活機制可知面對主機掉電,網線斷開情況時如果時間過長則會斷開連接,時間短則依然保持連接。?
?所以上述就是tcp的十大機制,對于tcp的報文結構我們還有三個沒講:
一個16位緊急指針和URG搭配使用,屬于tcp的特殊情況,這里不過多闡述,還有一個PSH,是催出對方盡快給自己返回回應,這里不詳細說了。
TCP和UDP的總結
TCP優勢:可靠傳輸,TCP 適用于絕大部分場景.
UDP優勢:更高效率,UDP 更適合于?對于"可靠性不敏感”,"性能敏感”場景
如果要傳輸比較大的數據包,TCP 更優先(UDP 有 64KB 的限制)如果要進行"廣播傳輸",優先考慮 UDP,UDP 天然支持廣播,TCP 不支持 (應用程序額外寫代碼實現)
有一種特殊的場景,需要把數據發給局域網的所有的機器.這個情況就是廣播
4.網絡層協議?
我們程序員主要還是以 應用層 和 傳輸層 為主.(都是和未來開發應用程序密切相關的),對于網絡層了解下就行。
網絡層要做的事情,主要是兩方面:
1.地址管理,制定一系列的規則, 通過地址,描述出網絡上一個設備的位置2.路由選擇.網絡環境比較復雜的,從一個節點到另一個節點之間,存在很多條不同的路徑,就需要通過這種方式,篩選/規劃出更合適的路徑進行數據傳輸?
網絡層的主要協議就是ip協議,其中又有兩個版本:ipv4和ipv6,這里我們主要講述ipv4版本。
?ipv4協議
以下是ipv4協議報文結構:
4位版本:
指定IP協議的版本,對于IPv4來說,就是4。如果是6,就是IPv6(上述是IPv4的報頭結構)4位頭部長度
描述報文頭部的長度,IP頭部最大長度是60字節,最短20個字節(因為選項部分所以可變)8位服務類型
其中有3位優先權字段(已經棄用),4位TOS字段和1位保留字段(保留字段留著之后用)
4位TOS分別表示:最小延時(傳輸過程中消耗時間最短),最大吞吐量(單位時間內傳輸的數據盡可能多),最高可靠性(降低丟包的概率),最小成本(比較節省系統開銷)。
這四者相互沖突,只能選擇一個。對于ssh/telnet這樣的應用程序,最小延時比較重要;對于ftp這樣的程序,最大吞吐量比較重要16位總長度
IP數據報整體占多少個字節(報頭+載荷)16位總長度是字節數,也就是前面說的UDP數據報最大64kb,那么這里也是IP數據包也不能超過64kb?
確實是不能超過64kb,IP數據報為了解決該問題,自主實現了拆包組包這樣的功能,如果攜帶的載荷,超出長度上線,IP就會自動拆分成多個數據包,每個數據包攜帶一部分,發送到對方之后在拼接好。
具體流程:
當前A給B傳輸一個數據,當前有一個TCP數據包,假設這個數據很長,超過了64kb
A這邊再封裝成IP數據包的時候,就會把TCP數據包拆成多分(假設3份),使用多個IP數據包進行發送
對于IP數據包來說,他并不關心所要傳輸的數據里面到底是什么樣的,直接簡單粗暴的把這個數據分成幾份,每一份都裝到IP的載荷里面,然后統一發送給B。
那么B是如何區分出拆分出的IP數據報?如何把拆分出的IP數據包進行合并?
IP報頭中的16位標識,3位標志位,13位片偏移這三個屬性就是用來實現IP的拆包組包的
16位標識:
唯一的標識主機發送的報文。如果IP報文在數據鏈路層被分片了,那么每一個片里面的這個id都是相同的。就是用來區分哪些數據包要合并3位標志字段:
第一位保留(保留的意思是現在不用,但是還沒想好說不定以后要用到)。第二位用來表示該數據包是否需要組包。第三位是結束標記位,當前包是否是最后一個需要組包的部分。13位分片偏移:
就是若干要拼接的數據包的先后順序,根據片偏移來區分出誰在前,誰在后。8位生存時間:
一個IP數據包,在網絡上有一個轉發的過程,轉發的數據是根據你設定好的目的IP來進行轉發,但是如果給定目的IP有問題,一直到不了的話,那會一直存在嗎?肯定不會的,所以這里的TTL就是限制一個數據包在網絡上轉發的最大次數。每經過一個路由器,次數就會消耗掉一次。一般是64(通常情況下64就夠用了),一旦達到0,這個數據包就會被丟棄掉。
8位協議:
描述了載荷部分是哪種協議的數據包,也就是交給UDP還是TCP,表示上層協議的類型。一個數據包在分用的時候,要交給上層哪個協議,都是有明確聲明的。16位頭部校驗和:
使用CRC進行校驗,這里檢驗的是報文頭部數據是否發生變化,載荷是否發生變化并不管(載荷的檢驗是到傳輸層去檢驗的)32位源地址和32位目標地址:
表示發送端和接收端的ip地址
講到ip地址,我們又要深入講一下。
ip地址為32位,那么32位也表示42億9000萬,原則上來說,不同設備,IP地址應該是唯一的,不重復,上述這個數字,在今天來說,顯然是不夠用的!!!當今社會,移動互聯網的發展,一個人就可能兩個手機。
那么如何解決該問題呢?
如何解決ip地址不夠的問題?
共有三個方案。
方案一:動態分配IP地址
某個設備,上網路由器就分配,不上網就不分配(這樣的機制只能緩解,不能從根本上解決)。
方案二:NAT機制網絡地址轉換(網絡地址映射)
NAT的核心思想是在一個網絡邊界路由器上維護一個地址轉換表,這個表記錄了內部私有IP地址與外部公有IP地址之間的映射關系。當內部網絡中的設備需要與外部網絡通信時,NAT會將數據包的源IP地址(內網地址)替換為公共IP地址,從而進行通信(內網 IP無法在廣域網上使用,所以必須轉換)
內網 IP (局域網 IP)如果一個 IP 地址,是以 10.*或者 172.16.*-172.31.*或者 192.168.*(復合上述條件之一,IP 就是內網 IP)
在同一個局域網內部,內網IP之間,不能重復。
在不同的局域網中, 內網 IP之間, 可以重復.內網 IP無法在廣域網上使用,只能在自己內部網使用,想和外部交流必須要用NAT轉換
外網 IP (廣域網 IP)剩下的 IP 就都是外網 IP,外網 IP 則始終都不允許重復
所以當前情況下,通常都是一個小區/一個學校/一個公司,都是構成一個大的局域網 ,這1個局域網中可能就有幾干上萬個設備,該設備里面的ip用的都是內網ip,而對于這樣的一個局域網,就使用一個外網 IP 即可,這樣就能進行通信了,內部的IP如果想要和廣域網中IP交流則用到NAT轉換就可以了。這樣就省了很多ip地址出來。
下面我們通過該圖片去看下NAT轉換
進行IP地址替換,本質上是為了讓一個公網IP地址,對應到多個設備,從而起到節省IP的效果.
當IP數據報到達服務器之后,只能看到源IP為1.2.3.4,無法感知最初局域網IP地址了。
從服務器中返回的IP數據報又怎樣返回到局域網設備呢?
路由器在進行NAT的時候,會把這次通信的相關信息記錄下來,從而能返回成功。
那么如果局域網內有很多臺設備呢?
大部分情況下,局域網內的不同設備,都是不同的內網ip,這個時候直接通過內網?IP 就能區分
少數情況下,如果是一個內網ip,就可以按照端口號來區分
極少數情況,碰巧訪問的是一個內網ip并且端口相同, 就可以在路由器這邊自動映射成不同的端口了,仍然能夠區分
注意:在NAT背景下通信
外網設備訪問外網設備,不需要任何的NAT,直接就能通信
內網設備或者外網設備訪問其他內網的設備是不被允許的。因為我們不清楚對方內網設備所屬的外網ip地址,所以不能發送。(知道了就可以發送出去)
內網設備訪問外網設備,對應的內網設備的路由器就會觸發NAT機制進行IP替換,此時就會給這個網絡數據的源IP替換成路由器字節的IP,能成功發送
NAT 機制最大的優勢就是局域網內部的設備能夠主動訪問外網的設備,外網的設備無法主動訪問局域網內部的設備(咱們之前寫的 UDP echo server 必須部署到云服務器上才能執行就是因為這個,它更好的保護了咱們電腦的安全)
當前的網絡世界,就是通過動態分配 + NAT機制解決IP不夠用的問題的
NAT機制確實能解決,但是這樣的方案又給網絡的復雜程度增加了不少,而且也沒有重根本上的解決,如果隨著設備進一步的增多,一個外網NAT設備上面最最多只能有6w多個表項,NAT也可能不夠用了。
所以就需要ipv6了
方案三:ipv6?
IPv6是使用16個字節(128位)來表示IP地址的,這就使IPv6可以表示的IP地址個數是一個天文數字了,給地球上的每一粒沙子都分配一個IPv6版本IP地址都是夠用的,雖說IPv6可以完美解決IP地址不夠用的問題,但是從IPv6被提出到現在真正被使用到的還是非常少的,現實中還是大量的使用IPv4版本的IP地址。
這主要還是IPv4和IPv6不兼容,想要大范圍的使用IPv6,就需要將原本的路由器等的網絡設備更換掉,這個更換的成本還是很大的,還有原因就是目前IPv6的各方面還沒有IPv4一樣成熟,效果跟ipv4一樣,所以普及程度少。
但是在中國, IPv6 的普及程度是非常高的70%以上注意,雖然 IPv6 看起來沒啥收益,但是發展 IPv6 卻是咱們國家互聯網行業中的一個重要政策,為了反制美國的霸權,IPv4 外網 IP 的分配是掌握在美國人手里的(雖然號稱是非營利組織,實際上背后的投資人就有美國軍方),ipv4上的DNS域名轉換也是如此,一旦得不到IP地址,會對國內互聯網行業造成毀滅性打擊,所以國家就發展ipv6,很大程度我們在這上面都有話語權,這樣就不會被掐脖子了,我們就能掌握ipv6上的地址分配,DNS域名轉換等技術。
對于我們電腦里的ipv6一般來說是需要手動設置之后,才能開啟的,開啟后其實也沒什么用。
ip地址的組成?
IP地址分為兩個部分,網絡號和主機號
網絡號:用來標識網段(標識一個局域網),保證相互連接的兩個網段具有不同的標識;
主機號:用來標識主機(標識一個局域網內部的主機),同一網段內,主機之間具有相同的網絡號,但是必須有不同的主機號下面給一個例子:
對于網絡號和主機號的劃分,主要有兩種分類方式,一種是通過IP地址分類(ABCDE),一種是子網掩碼。
子網掩碼?
子網掩碼格式和IP地址一樣,也是一個32位的二進制數,其中左邊是網絡號,用二進制數字"1"表示,1的數目等于網絡的長度;右邊是主機位,用二進制數字"0"表示,0的數目等于主機位的長度。家用網絡的子網掩碼一般都是255.255.255.0。
?IP地址的分類
這五類IP地址的前綴使用來區分類別的,每個類別下,網絡號和主機號長度都是固定的。AB類由于主機號太長,實際中很少有那么大的局域網,這就導致很多IP地址會被浪費掉?,這種分類方式在實際中被淘汰掉了
特殊IP地址?
主機號為0的IP:例如192.168.0.0 表示的就是網絡號,局域網里不應該存在某個主機的主機號為0
主機號為全1的IP:例如192.168.0.255,假定子網掩碼是255.255.255.0,這種稱為是廣播地址,(廣播地址就是往這個地址上發送UDP數據報,此時這個數據報就會被轉發給整個局域網中的所有主機,TCP不支持廣播。)
環回地址:IP以127開頭的,使用最多的是127.0.0.1,是指Windows系統自帶的虛擬網卡,這塊網卡于任何外部網絡不能通訊,只限于本機通訊。
路由選擇?
網絡層有兩件事,一件是地址管理,一個是路由選擇,地址管理我們剛才提了,現在來講講路由選擇:
路由選擇其實就是對數據在網絡中傳輸的路徑規劃,數據在發送的過程中,兩臺主機先是建立連接,兩臺主機都知道了對方的IP的地址,然后之后的每次數據傳輸過程中,由于網絡環境非常復雜,每個數據報傳輸的路徑不可能都相同,每條數據在網絡中進行傳輸的時候都會經歷網絡中的中間節點(路由器),這些結點是無法感知到網絡環境的全貌的,一個路由器最多只認識它的一些鄰居結點(或者是鄰居的鄰居),也就是說一個網絡設備是不可能有數據傳輸的完整路徑,當這些網絡設備知道了這個數據報的目的地址(目的IP),具體該怎樣走他會向鄰居結點進行詢問(就類似于我們日常生活中向別人問路)
路由選擇的核心思路就是"問路",每個路由器中都會有一個路由表這樣的數據結構用來記錄鄰居結點的信息,當一個IP數據報在進行網絡轉發的過程中,每個路由器在接收到這個IP數據報之后,就會將這個IP數據報中的目的IP與路由表中的信息進行比對,有匹配的結果就會按照當前路由器規劃的路徑傳輸,但是當前路由器的路由表中沒有匹配的信息,此時就會走路由器給你指出的一條默認的路徑(路由表的"下一跳表項"),這個下一跳表項就會將把這個IP數據報指引向更上一級的路由器(越上一級的路由器中的路由表中記錄的信息就會更多),這樣直到到達目的IP,當然也有到達不了的情況,因為每經過一個路由器問一次,生存的時間TTL就會減1,如果減到了0還沒有到達目標IP,就表示這個包永遠到不了了,這個包就會丟棄。
關于網絡層協議講的這些知識點,主要就是有一個簡單的了解即可,這些知識主要是“網管"需要重點掌握,咱們作為程序猿就只簡單了解即可?
5.數據鏈路層和物理層
數據鏈路層和物理層的主要協議有兩個:以太網協議和WiFi協議,它們兩種協議都是橫跨數據鏈路層和物理層的
那么它們有什么區別呢?
以太網協議主要用作有線網絡,WIFI協議主要用作無線網絡。這里我們主要講一下數據鏈路層中的以太網協議。
數據鏈路層中以太網數據幀的格式:?
一個完整的以太網數據幀是由幀頭(目的地址+源地址+類型)、幀尾(校驗和)和載荷構成。
其中這里的地址指的是mac地址,跟ip地址不一樣。mac地址和IP地址是兩套獨立的地址體系。
IP地址側重于全局轉發,從起點地址到目的地址的轉發;mac地址更側重于局部路徑的轉發,兩個相鄰設備的轉發。
mac 地址由于是 6 個字節(ip地址是兩個字節在ipv4中),能表示的范圍比 IP 地址大了很多(是其6w多倍)
IP 地址雖然早都不夠用了,但是 mac 還是夠用的. 目前來說,每個設備都是有唯一的 mac 地址
,并且在網卡出廠的時候,就寫死了其mac地址,一般來說也不能修改,所以mac也可以作為 一臺網絡設備的身份標識,mac 地址就屬于其中的一種定位身份的方式。
mac 地址通常是 十六進制 表示的兩個十六進制數字就是一個字節,字節和字節之間通常使用-或者:來分割
這里的類型則是上圖中的三種,0800類型則是最普通的數據幀(含有載荷),0806類型的數據幀則是ARP報文,?0835類型的數據幀則是一個RARP報文。這里不詳細介紹。
尾部的校驗和我就不多說了,都講過;
所以數據鏈路層中的以太網數據幀就講完了,物理層的以太網協議中的數據就更簡單,直接變為電信號,光信號去傳播,這里就不多說物理層了,沒什么好講的。
6.總結
這就是我們以上的內容,除了應用層,我們把每層的協議都詳細說了下,之后下篇文章我們將會重點再說下應用層的其他協議。