傳輸層位于OSI七層模型的第四層,TCP/IP四層模型的第三層。

傳輸層主要是給應用層提供通信服務的,是面向通信部分的最高層。在網(wǎng)絡編程中,一般使用的都是傳輸層暴露出來的接口。
在層次結(jié)構(gòu)這一章可知,傳輸層負責管理端到端的連接,主要面向終端設備。

這張圖想必會造成一個疑問,路由器都沒有傳輸層,那數(shù)據(jù)是怎么通過路由傳輸呢?
通過前面兩章的學習,我們可知,兩個主機進行網(wǎng)絡通信,需要經(jīng)過一些網(wǎng)絡和連接這些網(wǎng)絡的路由器。因為通信的起點和終點是兩臺主機,所以通信路徑中的所有路由器都是中間節(jié)點。那么不管這兩個主機采用何種協(xié)議(TCP或者UDP)進行數(shù)據(jù)傳輸,中間節(jié)點的工作內(nèi)容都是根據(jù)路由表來轉(zhuǎn)發(fā)IP數(shù)據(jù)報,這是IP協(xié)議的功能,而IP協(xié)議在網(wǎng)絡層。每個路由器在接收到比特流后,先按照數(shù)據(jù)幀來接收,再從數(shù)據(jù)幀中取出IP數(shù)據(jù)報,根據(jù)IP數(shù)據(jù)報首部的目的IP地址來查詢路由表,之后將IP數(shù)據(jù)報組裝成新的數(shù)據(jù)幀轉(zhuǎn)發(fā)出去。
所以傳輸層工作的本質(zhì)就是進行進程間的通信。
在操作系統(tǒng)相關的篇章中,我們知道一個計算機可以運行一個或多個進程。對于網(wǎng)絡通信,計算機之間是怎么標識進程的呢?這里引入端口(Port)的概念。端口使用16位比特位(0-65535)來表示。使用IP地址+端口的形式就可以唯一標識進程。
表格中是一些常見協(xié)議對應的端口。
| 協(xié)議 | FTP | HTTP | HTTPS | DNS | TELNET |
|---|---|---|---|---|---|
| 端口 | 21 | 80 | 443 | 53 | 23 |
UDP協(xié)議
UDP:User Datagram Protocol,用戶數(shù)據(jù)報協(xié)議。所謂數(shù)據(jù)報就是應用層傳過來的完整的數(shù)據(jù)。UDP是一個簡單地協(xié)議,它不會對數(shù)據(jù)報做任何處理(比如說合并、拆分之類),所以UDP數(shù)據(jù)報的長度由應用層傳過來的數(shù)據(jù)決定。
UDP是存放在IP數(shù)據(jù)報的數(shù)據(jù)部分的,而IP數(shù)據(jù)報文是存放在數(shù)據(jù)幀的數(shù)據(jù)中的,套娃過程如下:

接著來看下UDP報文的首部,UDP頭部信息很少,所以創(chuàng)建UDP報文其頭部開銷較小。

UDP是無連接的協(xié)議,發(fā)送數(shù)據(jù)報文比較隨意,想發(fā)就發(fā),發(fā)了也不關心你收到收不到,所以UDP不能保證可靠的交付數(shù)據(jù)。
UDP是面向數(shù)據(jù)報文的協(xié)議,應用層來的數(shù)據(jù)不做處理,直接塞到自己的數(shù)據(jù)段中。
UDP沒有擁塞控制(什么是擁塞控制會在TCP部分講解)。
可靠傳輸
TCP能保證數(shù)據(jù)可靠傳輸,在講解TCP之前我們先來了解下可靠傳輸?shù)母拍睢?/p>
最理想的傳輸有兩個特點:
1、傳輸信道不產(chǎn)生差錯;
2、不管發(fā)送方是否降低發(fā)送數(shù)據(jù)的速度,不需要采取任何措施就能夠?qū)崿F(xiàn)可靠傳輸。
然而實際中的網(wǎng)絡并不能夠達到這種理想的狀態(tài),但我們可以通過使用一些可靠傳輸?shù)膮f(xié)議去處理這些問題,比如規(guī)定如果發(fā)現(xiàn)發(fā)送的數(shù)據(jù)發(fā)生錯誤時讓發(fā)送方重新發(fā)送,這樣的協(xié)議有停止等待協(xié)議、連續(xù)ARQ協(xié)議。
停止等待協(xié)議
停止等待協(xié)議的主要實現(xiàn)思路就是發(fā)送方給接收方發(fā)送消息后就會停止發(fā)送,等待接收方發(fā)過來的確認消息。在收到接收方的消息后又會繼續(xù)發(fā)送消息,接著又會進行等待。
這是最簡單的可靠傳輸協(xié)議,但每發(fā)送一條消息都需要等待確認信息,所以對信道利用效率不高。

上圖一看就知道是理想、無差錯的狀況。
出錯的情況一般為,發(fā)送的消息丟失了、確認的消息丟失了、確認的消息很久才收到。
對上述情況的容錯處理主要表現(xiàn)為超時重傳,發(fā)送方每發(fā)送一條消息都會設置一個定時器(超時定時器),定時器到期還沒收到確認消息,就會重新發(fā)送數(shù)據(jù)。
連續(xù)ARQ協(xié)議
Automatic Repeat-reQuest,自動重傳請求。
停止等待協(xié)議是對單條信息進行發(fā)送和確認,所以效率不高。連續(xù)ARQ協(xié)議的思路就是批量發(fā)送信息再批量接收,這樣就提高了效率。
假設當前批量發(fā)送了5條消息。

當收到確認信息后,就會對下一組數(shù)據(jù)進行批量發(fā)送。雖然是批量接收確認信息,但它并不關心確認信息到底確認了哪條信息,而是會進行累計確認,我發(fā)送了5條數(shù)據(jù),也收到了5條確認信息,即代表本組數(shù)據(jù)發(fā)送成功,開始發(fā)送下一組數(shù)據(jù)。

這種操作被稱為滑動窗口。
TCP協(xié)議
TCP協(xié)議,即Transmission Control Protocol,傳輸控制協(xié)議,是計算機網(wǎng)絡中一個非常復雜的協(xié)議。同樣的,TCP數(shù)據(jù)報文也是放在IP數(shù)據(jù)報中:

TCP是面向連接的協(xié)議,可以進行全雙工的通信。在進行通信時,需要建立TCP的連接。一個連接有兩端,是點到點的通信。TCP不同于UDP,TCP提供可靠的傳輸服務。
在數(shù)據(jù)傳輸方面,TCP是面向字節(jié)流的協(xié)議。TCP的數(shù)據(jù)段中存放的是用戶數(shù)據(jù)的整體或部分數(shù)據(jù)流(TCP協(xié)議為了提高數(shù)據(jù)傳輸效率會對數(shù)據(jù)進行一些拆分、合并工作)。
TCP協(xié)議的頭部數(shù)據(jù)如下:

除去可選項和填充數(shù)據(jù),TCP首部固定20字節(jié)。
源端口:起始地址
目的端口:目的地址
序列號:初始值由系統(tǒng)隨機生成,隨后的值 = 初始值 + 發(fā)送的數(shù)據(jù)在整個數(shù)據(jù)流中的偏移量,這樣的設計可以保證數(shù)據(jù)傳輸不亂序。
32位使得其表示范圍位0~2^32-1
確認號:表示范圍位0~2^32-1,數(shù)據(jù)發(fā)送出去后,接受端給發(fā)送端的反饋機制。例如發(fā)送端發(fā)送了序列號為500,長度為100的數(shù)據(jù),
那么接收方會給發(fā)送方返回確認號600,表示其希望收到的數(shù)據(jù)首字節(jié)序號為600。簡而言之,確認號N表示N-1序號及其之前的數(shù)據(jù)都已收到。
數(shù)據(jù)偏移:表示真實的數(shù)據(jù)偏移首部的位置。占4位,可以表示0~15,單位為32位字,即每一個偏移量位4個字節(jié)。
保留字段:占6位,保留為今后使用,目前應設置為0
TCP標記:占6位,分別表示UGR、ACK、PSH、RST、SYN、FIN:
緊急UGR:當UGR置1時,發(fā)送應用進程就告訴發(fā)送方的TCP有緊急數(shù)據(jù)要傳送。于是發(fā)送方的TCP就把緊急
數(shù)據(jù)插入到本報文段數(shù)據(jù)的最前面,而在緊急數(shù)據(jù)后面的數(shù)據(jù)仍是普通數(shù)據(jù)。
確認ACK:確認報文段,僅當ACK=1時確認號字段才有效。當ACK=0時,確認號無效。
推送PSH:當兩個應用進程進行交互式的通信時,有時在一端的應用進程希望在鍵入一個命令后立即就能夠收到對方響應。
在這種情況下,TCP可 以使用PSUH(推送操作)。這時,發(fā)送方TCP把PSH置1,并立即創(chuàng)建一個報文段發(fā)送出去。接收方TCP收到PSH=1的報文段,
就盡快(推送)交付給接收應用進程,而不在等整個緩存都填滿了再向上交付。
復位RST:當RST=1時,表明TCP連接出現(xiàn)了嚴重差錯,必須釋放連接,然后重新建立新運輸連接。
RST=1還可以用來拒接一個非法報文段或拒絕打開一個連接。
同步SYN:在建立連接時用來同步序號。當SYN=1,ACK=0時,表明這是一個連接請求報文段;對方若同意連接,則應在相應的報文段中使SYN=1,ACK=1。
因此SYN置1就表示這是一個連接請求或連接接受報文段。
終止FIN:用來釋放一個連接,當FIN=1時,表明此報文段的發(fā)送方數(shù)據(jù)已經(jīng)發(fā)送完畢,并要求釋放運輸連接。
窗口:用于指明允許對方發(fā)送的數(shù)據(jù)量。
校驗和:CRC循環(huán)冗余檢測算法
緊急指針:指定緊急數(shù)據(jù)(URG=1)在報文的位置。
TCP選項:最多支持40字節(jié),用于支持未來的拓展。
填充:將數(shù)據(jù)填充成32位的整數(shù)倍。
可靠傳輸
我們知道TCP是可靠傳輸?shù)?,在了解上文的可靠傳輸基本原理后,我們繼續(xù)了解TCP協(xié)議是怎么保證可靠傳輸?shù)摹?/p>
根據(jù)上文的TCP報文頭不難看出TCP的可靠傳輸基于連續(xù)ARQ協(xié)議的,其滑動窗口以字節(jié)為單位。TCP首部由于有確認號的信息,這種確認機制使得其窗口的粒度變得很細。
假設現(xiàn)在窗口中的數(shù)據(jù)為1-5:

TCP協(xié)議不必等收到5次確認后再滑動窗口,假設現(xiàn)在收到了1和2的確認,窗口就會滑動(窗口首部收到了確認就會滑動)。

TCP支持選擇重傳,因此不必重傳窗口中所有的數(shù)據(jù),只需要按需重傳超時的數(shù)據(jù)即可(指定起始序號和終止序號重傳這一段數(shù)據(jù))。
流量控制
流量控制是控制發(fā)送方的發(fā)送速率,使其不要太快(不要超出接收方的最大接收速率),這個機制是使用滑動窗口來實現(xiàn)的。在前文中我們知道們了解到TCP協(xié)議的數(shù)據(jù)頭中有一個16位的窗口字段,這個字段就是指明允許對方發(fā)送的數(shù)據(jù)量。

由上圖我們可知,接收方在確認數(shù)據(jù)后,會告訴發(fā)送方它還能再接收多少的數(shù)據(jù)(窗口大?。=邮辗交貜痛翱跒?后,會在窗口可用時,給發(fā)送方發(fā)送消息,告知其窗口大小,這條消息無須確認。那么問題來了,這條消息丟失了怎么辦,這不死鎖了嗎?
這里使用了定時器的機制:當發(fā)送方收到窗口為0的消息時,會開啟一個定時器(堅持定時器),定時器每隔一段時間向發(fā)送方發(fā)送窗口探測報文,這樣就能知道窗口大小了。
擁塞控制
擁塞:每個通過網(wǎng)絡發(fā)送的包由于網(wǎng)絡中充塞著包而經(jīng)歷極長延遲的情況。類似于堵車。
通過流量控制的介紹我們可知,流量控制關注的是點對點之間的通信。
信息在網(wǎng)絡中傳輸,一條數(shù)據(jù)鏈路經(jīng)過了眾多設備,這些設備都有可能成為網(wǎng)絡傳輸?shù)钠款i。類似木桶的短板效應,一條數(shù)據(jù)鏈路的最大傳輸窗口為這條鏈路中所有設備的最小窗口。
擁塞控制考慮的是整個網(wǎng)絡,是全局性的考慮。對于擁塞控制的判斷方法很簡單粗暴(不考慮網(wǎng)絡故障的情況):我發(fā)送一個報文,如果報文超時了,那就代表發(fā)生了擁塞。
擁塞控制的算法有慢啟動算法和擁塞避免算法。
慢啟動算法
這是個比較簡單的算法,主要思想是由小到大逐漸增加發(fā)送的數(shù)據(jù)量,即每收到一個報文的確認,下次發(fā)送的報文數(shù)就再加一。發(fā)送的數(shù)據(jù)量先會以2的指數(shù)級增長到達閾值(慢啟動閾值 ssthresh)。
擁塞避免算法
慢啟動達到閾值后就會使用擁塞避免算法,該算法會維護一個擁塞窗口的變量,只要網(wǎng)絡不擁塞,就試探著將擁塞窗口調(diào)大。直到將最大擁塞窗口試出來。
舉例:擁塞避免算法 - ggjucheng - 博客園 (cnblogs.com)

在該圖中,假定當cwnd為32個報文段時就會發(fā)生擁塞,最大擁塞窗口為31。
根據(jù)慢啟動算法可知,在第四次時達到了閾值16。接著使用擁塞避免算法,每次將窗口調(diào)大1,窗口調(diào)到32時發(fā)生了擁塞,此時可知擁塞窗口為31。
三次握手
先來回顧下TCP報文頭部的TCP標記字段,TCP建立連接需要三次握手,用到的標記為ACK、SYN、FIN。

三次握手的過程如下:

第1次握手:發(fā)送方發(fā)出一個SYN報文,報文中有自己的序列號seq = x,發(fā)送方進入同步已發(fā)送狀態(tài);
第2次握手:接收方接收消息后會被動的打開TCP連接,同時發(fā)送確認報文。SYN = 1表示這是一個連接請求報文,ACK = 1表示確認號生效,ack = x + 1表示確認號,接收方還會發(fā)送自己的序列號seq = y。接收方進入同步已接收狀態(tài)。
第3次握手:發(fā)送方對接收方第二次握手的確認。
通過第2、3次握手兩次ACK確認操作,發(fā)送方和接收方都知道了各自的序列號seq是多少。
為什么需要第3次握手?
先說結(jié)論:第三次握手可以避免已經(jīng)失效的請求報文傳到接收方,引起錯誤。
假設不需要三次握手,兩次握手即可建立連接。那么當接收方發(fā)送完確認報文后,即代表連接已建立。
如果發(fā)送方發(fā)送的請求報文在網(wǎng)絡中發(fā)生了超時,根據(jù)前面的可靠傳輸部分可知,發(fā)送方會重傳請求報文。
接收方會對重傳的報文進行確認,建立了連接。此時第一次發(fā)送的請求報文到達了接收方,接收方會進行確認,然后就又建立了連接。
現(xiàn)在回到三次握手的情況,發(fā)送方超時重傳了請求報文,接著接收方發(fā)送了確認報文,然后發(fā)送方發(fā)送了確認報文,建立連接。
同樣的超時的報文到達了接收方,接收方回復了確認報文,發(fā)送方收到確認報文后,由于該報文之前因為超時重傳過,發(fā)送方不會再給接收方發(fā)送確認報文(第三次握手),也就避免了連接的建立。
四次揮手
TCP連接釋放需要進行四次揮手,過程如下:

簡要的介紹下過程:
數(shù)據(jù)傳輸完成,需要釋放連接時,發(fā)送方會發(fā)送一個FIN報文,用于通知接收方它沒有數(shù)據(jù)需要發(fā)送了,接收方回復確認。
接收方將數(shù)據(jù)處理好后,給接收方發(fā)送消息,通知發(fā)送方它沒有數(shù)據(jù)要處理了,可以釋放連接。發(fā)送方回復確認,接收方收到后立即關閉連接。發(fā)送方回復完確認后會開啟等待定時器,在兩個最長報文生命周期(MSL,建議設置為2分鐘)后,發(fā)送方關閉連接。
為什么需要等待2MSL呢?
由圖可知發(fā)送方發(fā)送的最后一個報文是沒有確認的,等待主要是為了這個報文能被接收方收到。2MSL時間內(nèi)接收方?jīng)]有收到確認就會重傳請求報文,等待發(fā)送方重新確認。另外就是MSL是報文最長生命周期,等待2MSL是確保所有報文都過期。
定時器
前文中提及了三個定時器:超時定時器、堅持定時器、等待定時器,現(xiàn)在系統(tǒng)的講解下TCP協(xié)議中的定時器。
超時定時器
在截止時間(通常為60秒)到之前,已經(jīng)收到了對此特定報文段的確認,則撤銷計時器;截止時間到了,但沒有收到對此特定報文段的確認,則重傳報文段,并且將計時器復位。
堅持定時器
主要解決零窗口大小通知可能導致的死鎖問題,當接收端的窗口大小為0時,接收端向發(fā)送端發(fā)送一個零窗口報文段,發(fā)送端即停止向?qū)Χ税l(fā)送數(shù)據(jù)。此后,如果接收端緩存區(qū)有空間則會重新給發(fā)送端發(fā)送一個窗口大小,即窗口更新。但接收端發(fā)送的這個確認報文段有可能會丟失,而此時接收端不知道已經(jīng)丟失并認為自己已經(jīng)發(fā)送成功,則一直處于等待數(shù)據(jù)的狀態(tài);而發(fā)送端由于沒有收到該確認報文段,就會一直等待對方發(fā)來新的窗口大小,這樣一來,雙方都處在等待對方的狀態(tài),這樣就形成了一種死鎖問題。如果沒有應對措施,這種局面是不會被打破的。為了解決這種問題,TCP為每一個連接設置了堅持計時器。
當發(fā)送端TCP收到接收端發(fā)來的零窗口通知時,就會啟動堅持計時器。當計時器的期限到達時,發(fā)送端就會主動發(fā)送一個特殊的報文段告訴對方確認已經(jīng)丟失,必須重新發(fā)送。
等待計時器
TCP關閉連接并不是立即關閉的,在等待期間,連接還處于過渡狀態(tài)。2MSL時間內(nèi)接收方?jīng)]有收到確認就會重傳請求報文,等待發(fā)送方重新確認,同時等待2MSL可以確保發(fā)送&接收兩方所有報文都過期。
?;钣嫊r器
主要是為了防止兩個TCP連接出現(xiàn)長時間的空閑,例如當一方出現(xiàn)狀態(tài)變化或故障,另一方?jīng)]有察覺的情況。
假設連接雙方在建立連接后,只傳輸了-些數(shù)據(jù),然后就都保持靜默了,雙方也都沒有關閉連接(這種情況經(jīng)常存在) 。如果這個時候其中一方已經(jīng)故障, 那么這個連接將會永遠被打開,如果被連接的一方是服務端的話, 那將浪費很多服務端的資源。 因此為了解決這個問題,服務端般都會設置1個?;疃〞r器,每次收對方的數(shù)據(jù)則重置這個定時器,如果定時器超時,服務端則發(fā)送探測報文段,探測客戶端是否還在線,如果沒有收到響應的話,那么則認為客戶端已經(jīng)斷開連接了,因此服務端也