概述:在協議棧中,運輸層恰好位於網絡層之上。網絡層提供了主機之間的邏輯通訊,而運輸層爲運行在不一樣主機上的進程之間提供了邏輯通訊。緩存
比如兩個家庭的孩子互相寫信,而後由某一個大孩子負責將全部的信交到郵局和從郵局收集到全部人的信而後分發給各個孩子。中間的傳輸則交給郵局來處理。此處,服務器
應用層報文=信封上的字符進程=堂兄弟姐妹網絡
主機(又稱爲端系統)=家庭tcp
運輸層協議=負責收發的兩個大孩子spa
網絡層協議=郵政服務(包括郵車)線程
*注:而對於不一樣的運輸層協議,就比如不一樣的大孩子,可能這些大孩子比較粗心,會有遺漏,或者有丟失。code
運輸協議可以提供的服務經常受制於底層網絡層協議的服務模型。若是網絡層協議沒法爲主機之間發送的運輸層報文段提供時延或帶寬保證的話,運輸層協議也就沒法爲進程之間發送的應用程序報文提供時延或帶寬保證。blog
服務擴展:將兩個端系統間IP的交付服務擴展爲運行在端系統上的兩個進程之間的交付服務進程
進程,套接字,端口號:一個進程對應一個端口號,可是一個端口號能夠對應於多個套接字。ip
多路複用和多路分解是在套接字層面進行討論的,多路分解:從網絡層傳輸上來的信息可能來自不一樣主機,或同一主機的不一樣進程,要把這些報文段發向正確的進程,這就是多路分解,將信息分揀出來。多路複用:同理,在源主機從不一樣套接字中收集數據塊,併爲每一個數據塊封裝上首部信息(這將在之後用於分解)從而生成報文段,而後將報文段傳遞到網絡層。
端口號分配:若是應用程序開發者所編寫的代碼實現的是一個「周知協議」的服務器端,那麼開發者就必須爲其分配一個相應的周知端口號。一般,應用程序的客戶端讓運輸層自動地(並 且是透明地)分配端口號,而服務器端則分配一個特定的端口號。
一個UDP套接字是由一個二元組(目的IP地址,目的端口號)識別的,即當兩個具備相同的目的IP地址和目的端口號發至這個主機的網絡層時,運輸層將把它們發往相同的目的套接字和相同的目的進程。 原端口號和原IP地址的做用主要是當以前的接收方須要回發一個報文給以前的發送方式,能夠從以前的報文中獲取相關信息。
一個TCP套接字是由一個四元組(源IP地址,源端口號,目的IP地址,目的端口號)識別的。因此即便兩個TCP報文段具備相同的目的IP地址,目的端口號,若是他們來自於不一樣的IP地址或者不一樣的端口號,那麼他們就會被定向到不一樣的套接字。問題:進程、端口號、套接字的對應關係?以服務器做爲主角,當有兩個不一樣用戶訪問同一個服務器上的同一個進程時,這時由TCP套接字的標識可知,服務器會新建一個套接字以供服務,這就是線程。
運輸層最低限度必須提供一種複用/分解服務,以便在網絡層與正確的應用級進程之間傳遞數據。 而UDP只是作了運輸協議可以作的最少工做:複用/分解功能及少許的差錯檢測外。
無鏈接:使用UDP時,在發送報文段以前,發送方和接收方的運輸層實體之間沒有握手。如使用了UDP協議的DNS。
主機端的UDP爲查詢報文添加首部字段,而後將造成的報文段交給網絡層。網絡層將此UDP報文段封裝進一個IP數據報中,而後將其發送給一個名字服務器。在查詢主機中的DNS應用程序則 等待對該查詢的響應。若是它沒有收到響應(多是因爲底層網絡丟失了查詢或響應),則要麼試圖向 另外一個名字服務器發送該査詢,要麼 通知調用的應用程序它不能得到響應。
### UDP報文段結構:todo
### UDP檢驗和
發送方的UDP對報文段中的全部16比特字的和,在計算和的時候,對溢出的進位進行回捲(也就是把溢出的數字再加到數字的尾部,反覆循環直至沒有溢出),計算完和以後再對這個和取反獲得的結構就是檢驗和。在接收方UDP將傳輸過來的全部16比特字再進行求和並將檢驗和也一併求和,最後得出的結果若爲16個1則代表沒有出錯,如有0則代表出錯了。
端到端原則的體現:在既沒法確保逐鏈路的可靠性,又沒法確保內存中的差錯檢測的狀況下,若是端到端數據傳輸服務要提供差錯檢測,UDP就必須在端到端基礎上在運輸層提供差錯檢測。與在較高級別提供這些 功能的代價相比,在較低級別上設置的功能多是冗餘的或幾乎沒有價值的。可是UDP的對差錯的恢復無能爲力,它只能作到丟棄受損的報文段,或者將受損的報文段交給應用程序並給出警告。
rdt1.0:假設信道是徹底可靠的,即在傳輸過程當中不存在出錯,那麼發送方發完以後就萬事大吉了,直接等到上一層的新數據。
對於如何判斷數據包是否產生錯誤,採用的是以前講過的校驗碼checksum
rdt2.0:由於信道不多是徹底可靠的,因此在傳輸的過程當中,經過NAK和ACK做爲反饋信號,當接收了而且是未損壞的數據時,則向發送發返回一個ACK,過程結束。若接受了可是是損壞的數據時,則向發送方返回一個NAK,接收方等待,發送方進行重傳操做。問題:停等,NAK/ACK出錯的話會產生混亂。
利用狀態進行判斷,之前的話只是經過驗證碼NAK/ACK進行判斷,如今增強,不只僅看驗證碼還要看當前所處的狀態與傳過來的驗證碼是否匹配。
rdt2.1:主要解決的是2.0中出現的反饋信息出錯的問題,添加了01編號,也就是說01分別表明兩個數據包,而後這樣循環往復。①那麼發送的人發送0號數據包,發送的的人開始等待反饋信息,此時接受者若接收到0號數據包未損壞,則返回ACK,可是ACK在途中發生錯誤跳轉成了NAK或損失成亂七八糟的東西,此時發送方進行重傳0號數據包,到了接收方,可是由於接收方以前正確接受了0號數據包處於等待1號數據包的狀態,因此會出現拒收,避免冗餘。②發送的人發送0號數據包,可是由於有損傷因此接收方發送NAK,可是若NAK變成了ACK,此時發送方就繼續發送1號數據包了,因爲接受者還處於接收0號數據包的狀態,因此會拒絕1號數據包,避免錯序。
rdt2.1中
ss發送0號數據包,rr收到以後發現損壞返回NAK並進入等待0號數據包,可是NAK在途中跳轉成了ACK,ss收到ACK以後發送1號數據塊,rr接收到1號數據塊以後返回ACK,ss接收到ACK就繼續循環了,那麼0號數據包不就一直沒傳過去嘛?也就是說,我感受ss沒法判斷rr傳過來的是對0號數據的ACK仍是對1號數據的ACK啊解答:用checksum對反饋數據進行檢驗,因此即便是NAK轉變成了ACK,ss仍是會判斷他是錯的,因此仍是會進行重發。
rdt2.2:其實仔細分析以上的狀態轉換會發現,接受者發送NAK/ACK代表的意思不就是我還想要當前數據包再給我重發一份和我已經接收了當前數據包你能夠發下一份了。那麼在2.2中,ss會在發送的數據包進行01編號,對於rr而言,只要你的數據包有損壞或者你發的不是rr當前所處狀態的數據包(好比說rr處在接收0號數據包的狀態結果傳來了1號數據包或者0號有損數據包,那麼我就返回ACK,1就行了,這個1既能夠表明有損,也能夠表明傳錯),由於這樣的一個返回對ss來講都是進行一樣的操做也就是重傳。也至關於將2.1rr端的幾種狀況進行合併,由於這對ss而言所作的操做是同樣的。問題:既然每次返回都是ACK,ACK還有什麼存在的意義呢?
rdt3.0:這就比較好理解了,在2.2的基礎上(可以處理冗餘數據包)若數據包卡在了傳輸路上或者反饋信號卡住了,那麼一直等下去畢竟不是個辦法,因此增長了一個定時功能,若反饋信號在時間內都沒有到達的話就直接重傳。
### 流水線(pipelining)操做:
解決了2.0中就出現的停等問題,停等的話ss必須得等到返回當前數據包的一個正向反饋爲止。也就是在一個RTT的時間內都須要在等待,而流水線則是在這個RTT中反覆發送多個分組,而後以後再等反饋信息。
回退N步-GBN
N的含義:由於在RTT中能夠反覆發送多個分組,可是我須要發完分組後收到分組的正反饋而後繼續發送。那麼GBN就是在流水線中未確認的分組數不能超過某個最大容許數N。
選擇重傳-SR
一條TCP鏈接的時候都會爲接收方和發送方配備一個接收緩存,當對方發送的數據過快時,可將收到的數據先暫時放在緩存中,而後上層一點一點讀取。這裏不與以前說的亂序包裹產生衝突,亂序包裹應該也是放在這個緩存中,等待失序的包裹到來時,一塊兒交付給上層。流量控制就是爲了控制這個緩存空間不會被溢出,由於溢出了接下來的包裹就會被丟棄。
假設主機A向主機B發送一個大文件。主機B會對本身的接收緩存設置兩個變量:
並用RcvBuffer表示緩存空間的大小。顯然可知:
LastByteRcvd - LastByteRead<=RcvBuffer
由此可計算出B的緩存可用可見,用接收窗口rwnd表示:
rwnd = RcvBuffer - [ LastByteRcvd - LastByteRead ],
主機B會將rwnd的值放入它發給主機A的報文段接收窗口字段中,也就是告知主機A我還有多少的空間供你使用。
同理,主機A的緩存空間也有兩個變量:LastByteSent和LastByteAcked,也就是最後發送和最後被正確接收的,易得LastByteSent-LastByteAcked也就是發送還爲接收的數據,控制LastByteSent-LastByteAcked這個數據的大小要小於rwnd便可。
但實際上還有一個小bug,就是rwnd是須要依附在B向A發送的報文段上的,若B的緩存空間已滿,在告知A本身rwnd已經爲0以後,再也不向A發送任何反饋信息。這時的A就至關於被阻塞了而不能再發送數據。(B將數據收到緩存中就會向A發送ACK了)
解決:TCP規範中要求:當主機B的接收窗口爲0時,主機A繼續發送只有一個字節數據的報文段。這些報文段將會被接收方確認。最終緩存將開始清空,而且確認報文裏將包含一個非0的 rwnd 值。