考慮最簡單的狀況:兩臺主機之間的通訊。這個時候只須要一條網線把二者連起來,規定好彼此的硬件接口,如都用USB、電壓10v、頻率2.4GHz等,這一層就是物理層,這些規定就是物理層協議。android
咱們固然不知足於只有兩臺電腦鏈接,所以咱們可使用交換機把多個電腦鏈接起來,以下圖:web
這樣鏈接起來的網絡,稱爲局域網,也能夠稱爲以太網(以太網是局域網的一種)。在這個網絡中,咱們須要標識每一個機器,這樣才能夠指定要和哪一個機器通訊。這個標識就是硬件地址MAC。設計模式
硬件地址隨機器的生產就被肯定,永久性惟一。在局域網中,咱們須要和另外的機器通訊時,只須要知道他的硬件地址,交換機就會把咱們的消息發送到對應的機器。緩存
這裏咱們能夠無論底層的網線接口如何發送,把物理層抽離,在他之上建立一個新的層次,這就是數據鏈路層。微信
咱們依然不知足於局域網的規模,須要把全部的局域網聯繫起來,這個時候就須要用到路由器來鏈接兩個局域網:網絡
可是若是咱們仍是使用硬件地址來做爲通訊對象的惟一標識,那麼當網絡規模愈來愈大,須要記住全部機器的硬件地址是不現實的;併發
同時,一個網絡對象可能會頻繁更換設備,這個時候硬件地址表維護起來更加複雜。這裏使用了一個新的地址來標記一個網絡對象:IP地址。socket
經過一個簡單的寄信例子來理解IP地址。spa
我住在北京市,我朋友A住在上海市,我要給朋友A寫信:計算機網絡
所以,這裏IP地址就是一個網絡接入地址(朋友A的住址),我只須要知道目標IP地址,路由器就能夠把消息給我帶到。在局域網中,就能夠動態維護一個MAC地址與IP地址的映射關係,根據目的IP地址就能夠尋找到機器的MAC地址進行發送。
這樣咱們不需管理底層如何去選擇機器,咱們只須要知道IP地址,就能夠和咱們的目標進行通訊。這一層就是網絡層。網絡層的核心做用就是提供主機之間的邏輯通訊。
這樣,在網絡中的全部主機,在邏輯上都鏈接起來了,上層只須要提供目標IP地址和數據,網絡層就能夠把消息發送到對應的主機。
一個主機有多個進程,進程之間進行不一樣的網絡通訊,如邊和朋友開黑邊和女友聊微信。個人手機同時和兩個不一樣機器進行通訊。
那麼當個人手機收到數據時,如何區分是微信的數據,仍是王者的數據?那麼就必須在網絡層之上再添加一層:運輸層:
運輸層經過socket(套接字),將網絡信息進行進一步的拆分,不一樣的應用進程能夠獨立進行網絡請求,互不干擾。
這就是運輸層的最本質特色:提供進程之間的邏輯通訊。這裏的進程能夠是主機之間,也能夠是同個主機,因此在android中,socket通訊也是進程通訊的一種方式。
如今不一樣的機器上的應用進程之間能夠獨立通訊了,那麼咱們就能夠在計算機網絡上開發出形形式式的應用:如web網頁的http,文件傳輸ftp等等。這一層稱爲應用層。
應用層還能夠進一步拆分出表示層、會話層,但他們的本質特色都沒有改變:完成具體的業務需求 。和下面的四層相比,他們並非必須的,能夠歸屬到應用層中。
最後對計網分層進行小結:
這裏須要注意的是,分層並非在物理上的分層,而是邏輯上的分層。經過對底層邏輯的封裝,使得上層的開發能夠直接依賴底層的功能而無需理會具體的實現,簡便了開發。
這種分層的思路,也就是責任鏈設計模式,經過層層封裝,把不一樣的職責獨立起來,更加方便開發、維護等等。
TCP並非把應用層傳輸過來的數據直接加上首部而後發送給目標,而是把數據當作一個字節 流,給他們標上序號以後分部分發送。這就是TCP的面向字節流特性:
面向字節流的好處是無需一次存儲過大的數據佔用太多內存,壞處是沒法知道這些字節表明的意義,例如應用層發送一個音頻文件和一個文本文件,對於TCP來講就是一串字節流,沒有意義可言,這會致使粘包以及拆包問題,後面講。
前面講到,TCP是可靠傳輸協議,也就是,一個數據交給他,他確定能夠完整無誤地發送到目標地址,除非網絡炸了。他實現的網絡模型以下:
對於應用層來講,他就是一個可靠傳輸的底層支持服務;而運輸層底層採用了網絡層的不可靠傳輸。雖然在網絡層甚至數據鏈路層就可使用協議來保證數據傳輸的可靠性,但這樣網絡的設計會更加複雜、效率會隨之下降。把數據傳輸的可靠性保證放在運輸層,會更加合適。
可靠傳輸原理的重點總結一下有:滑動窗口、超時重傳、累積確認、選擇確認、連續ARQ。
要實現可靠傳輸,最簡便的方法就是:我發送一個數據包給你,而後你跟我回復收到,我繼續發送下一個數據包。傳輸模型以下:
這種「一來一去」的方法來保證傳輸可靠就是中止等待協議(stop-and-wait)。不知道還記不記得前面TCP首部有一個ack字段,當他設置爲1的時候,表示這個報文是一個確認收到報文。
而後再來考慮另外一種狀況:丟包。網絡環境不可靠,致使每一次發送的數據包可能會丟失,若是機器A發送了數據包丟失了,那麼機器B永遠接收不到數據,機器A永遠在等待。
解決這個問題的方法是:超時重傳。當機器A發出一個數據包時便開始計時,時間到還沒收到確認回覆,就能夠認爲是發生了丟包,便再次發送,也就是重傳。
但重傳會致使另外一種問題:若是原先的數據包並無丟失,只是在網絡中待的時間比較久,這個時候機器B會受到兩個數據包,那麼機器B是如何辨別這兩個數據包是屬於同一份數據仍是不一樣的數據?
這就須要前面講過的方法:給數據字節進行編號。這樣接收方就能夠根據數據的字節編號,得出這些數據是接下來的數據,仍是重傳的數據。
在TCP首部有兩個字段:序號和確認號,他們表示發送方數據第一個字節的編號,和接收方期待的下一份數據的第一個字節的編號。
中止等待協議已經能夠知足可靠傳輸了,但有一個致命缺點:效率過低。發送方發送一個數據包以後便進入等待,這個期間並無幹任何事,浪費了資源。解決的方法是:連續發送數據包。模型以下:
和中止等待最大的不一樣就是,他會源源不斷地發送,接收方源源不斷收到數據以後,逐一進行確認回覆。這樣便極大地提升了效率。但一樣,帶來了一些額外的問題:
發送是否能夠無限發送直到把緩衝區全部數據發送完?不能夠。由於須要考慮接收方緩衝區以及讀取數據的能力。若是發送太快致使接收方沒法接受,那麼只是會頻繁進行重傳,浪費了網絡資源。因此發送方發送數據的範圍,須要考慮到接收方緩衝區的狀況。這就是TCP的流量控制。
解決方法是:滑動窗口。基本模型以下:
在TCP的首部有一個窗口大小字段,他表示接收方的剩餘緩衝區大小,讓發送方能夠調整本身的發送窗口大小。經過滑動窗口,就能夠實現TCP的流量控制,不至於發送太快,致使太多的數據丟失。
連續ARQ帶來的第二個問題是:網絡中充斥着和發送數據包同樣數據量的確認回覆報文,由於每個發送數據包,必須得有一個確認回覆。提升網絡效率的方法是:累積確認。
接收方不須要逐個進行回覆,而是累積到必定量的數據包以後,告訴發送方,在此數據包以前的數據全都收到。例如,收到 1234,接收方只須要告訴發送方我收到4了,那麼發送方就知道1234都收到了。
第三個問題是:如何處理丟包狀況。在中止等待協議中很簡單,直接一個超時重傳就解決了。但,連續ARQ中不太同樣。
例如:接收方收到了 123 567,六個字節,編號爲4的字節丟失了。按照累積確認的思路,只能發送3的確認回覆,567都必須丟掉,由於發送方會進行重傳。這就是GBN(go-back-n) 思路。
可是咱們會發現,只須要重傳4便可,這樣不是很浪費資源,因此就有了:選擇確認SACK 。在TCP報文的選項字段,能夠設置已經收到的報文段,每個報文段須要兩個邊界來進行肯定。這樣發送方,就能夠根據這個選項字段只重傳丟失的數據了。
到這裏關於TCP的可靠傳輸原理就已經介紹得差很少。最後進行一個小結:
固然,這只是可靠傳輸的冰山一角,感興趣能夠再深刻去研究。
來源:https://www.toutiao.com/i6954...