
本文已經(jīng)優(yōu)先發(fā)表在掘金,請不要重讀,浪費時間哦
點個贊收藏吧
傳輸層
本文主要講的是傳輸中的兩大重要協(xié)議TCP和UDP,雖然在Android開發(fā)中,并不需要了解到這么底層,但有理論的支撐,寫代碼總是很自信的啦。理論指導著實踐,實踐是理論檢驗的唯一標準。站在巨人的肩膀窺伺網(wǎng)絡(luò)世界。
用戶數(shù)據(jù)報協(xié)議UDP
用戶數(shù)據(jù)報協(xié)議UDP只在IP的數(shù)據(jù)報服務(wù)至上增加了復(fù)用和分用的功能以及差錯檢測的功能。只有面向無連接的報文,不可靠傳輸?shù)奶攸c。UDP對應(yīng)用層交下來的數(shù)據(jù)只添加首部,并進行特別的處理,就交給網(wǎng)絡(luò)層;對網(wǎng)絡(luò)層傳遞上來的用戶數(shù)據(jù)報拆封首部后,原封不動的交給應(yīng)用層。
1、UDP的首部格式
用戶數(shù)據(jù)報UDP分為兩個字段:數(shù)據(jù)字段和首部字段,從圖來分析用戶數(shù)據(jù)報UDP的首部格式。
UDP首部字段很簡單,由4個字段組成,每個字段的長度都是兩個字節(jié),共8字節(jié)。
- 源端口 原端口號,在需要對方回信時選用,不需要時可全0
- 目的端口 目的端口號,這在終點交付報文時必須使用,不然數(shù)據(jù)交給誰呢?
- 長度 UDP的長度,最小值為8字節(jié),僅有首部
- 檢驗和 檢測用戶數(shù)據(jù)報在傳輸過程是否有錯,有錯就丟棄。
在傳輸?shù)倪^程中,如果接收方UDP發(fā)現(xiàn)收到的報文中的目的端口不存在,會直接丟棄,然后由網(wǎng)際控制報文協(xié)議ICMP給發(fā)送方發(fā)送“端口不可達”差錯報文。
2、偽首部
計算校驗和時,需要在UDP之前增加12個字節(jié)的偽首部。這種首部并不是用戶數(shù)據(jù)報的真正首部。偽首部并不在網(wǎng)絡(luò)中傳輸,只是在計算檢驗和,臨時添加在UDP用戶數(shù)據(jù)報前,得到一個臨時的用戶數(shù)據(jù)報。
UDP的校驗和是把首部和數(shù)據(jù)部分一起校驗,發(fā)送方計算校驗和的一般步驟:
- 將首部的校驗和字段填充為0(零)
- 把偽首部和用戶數(shù)據(jù)報UDP看出16位的字符串連接起來
- 如果數(shù)據(jù)部分不是偶數(shù)字節(jié),則填充一個全零字節(jié)(該字節(jié)不發(fā)送到網(wǎng)絡(luò)層)
- 按二進制反馬計算出這些16位字的和
- 然后將和寫入校驗和字段,就可以發(fā)送到網(wǎng)絡(luò)層了。
接收方收到用戶數(shù)據(jù)報后,連同偽首部一起,按二進制反碼求這些16位字的和,無差錯結(jié)果是應(yīng)全為1.否則出錯,直接丟棄該報文。
TCP協(xié)議
TCP協(xié)議作為傳輸層主要協(xié)議之一,具有面向連接,端到端,可靠的全雙工通信,面向字節(jié)流的數(shù)據(jù)傳輸協(xié)議。
1、TCP報文段
雖然TCP面試字節(jié)流,但TCP傳輸?shù)臄?shù)據(jù)單元卻是報文段。TCP報文段分為TCP首部和數(shù)據(jù)部分,TCP報文段首部的前20個字節(jié)是固定的,后面有4n字節(jié)是更具需要而增加的選項,最大為40字節(jié)。
- 源端口和目的端口 各占兩個字節(jié),TCP的分用功能也是通過端口實現(xiàn)的。
- 序號 占4個字節(jié),范圍是[0,232],TCP是面向字節(jié)流的,每個字節(jié)都是按順序編號。例如一個報文段,序號字段是201,攜帶數(shù)據(jù)長度是100,那么第一個數(shù)據(jù)的序號就是201,最后一個就是300。當達到最大范圍,又從0開始。
- 確認號 占4個字節(jié),是期望收到對方下一個報文段的第一個字節(jié)的序號。若確認號=N,則表示序號N前所有的數(shù)據(jù)已經(jīng)正確收到了。
- 數(shù)據(jù)偏移 占4位,表示報文段的數(shù)據(jù)部分的起始位置,距離報文段的起始位置的距離。間接的指出首部的長度。
- 保留 占6位,保留使用,目前為0.
- URG(緊急) 當URG=1,表明緊急指針字段有效,該報文段有緊急數(shù)據(jù),應(yīng)盡快發(fā)送。
- ACK(確認) 僅當ACK=1時,確認號才有效,連接建立后,所有的報文段ACK都為1。
- PSH(推送) 接收方接收到PSH=1的報文段,會盡快交付接收應(yīng)用經(jīng)常,不再等待整個緩存填滿再交付。實際較少使用。
- RST(復(fù)位) RST=1時,表明TCP連接中出現(xiàn)嚴重差錯,必須是否連接,再重連。
- SYN(同步) 在建立連接時用來同步序號。當SYN=1,ACK=0,則表明是一個連接請求報文段。SYN=1,ACK=1則表示對方同意連接。TCP建立連接用到。
- FIN(終止) 用來釋放一個連接窗口。當FIN=1時,表明此報文段的發(fā)送方不再發(fā)送數(shù)據(jù),請求釋放單向連接。TCP斷開連接用到。
- 窗口 占2個字節(jié),表示自己的發(fā)送方自己的接收窗口,窗口值用來告訴對方允許發(fā)送的數(shù)據(jù)量。
- 校驗和 占2字節(jié),檢驗和字段查驗范圍包括首部和數(shù)據(jù)部分。
- 緊急指正 占2字節(jié),URG=1時,緊急指針指出本報文段中的緊急數(shù)據(jù)的字節(jié)數(shù)(緊急字節(jié)數(shù)結(jié)束后為普通字節(jié))。
- 選項 長度可變,最長可達40字節(jié)。例如最大報文段長度MSS。MSS指的是數(shù)據(jù)部分的長度而不是整個TCP報文段長度,MSS默認為536字節(jié)長。窗口擴大,時間戳選項等。
2、TCP建立連接-三次握手
三次握手圖例如下,與文字解釋配合使用效果更佳。
第一次:客戶端發(fā)送連接請求報文給服務(wù)端,其中SYN=1,seq=x。發(fā)送完畢后進入YSN_END狀態(tài)。
第二次:服務(wù)端接收到報文后,發(fā)回確認報文,其中ACK=1,ack=x+1,因為需要客戶端確認,所以報文中也有SYN=1,seq=y的信息。發(fā)送完后進入SYN_RCVD狀態(tài)。
第三次:客戶端接收到報文后,發(fā)送確認報文,其中ACK=1,ack=y+1。發(fā)送完客戶端進入ESTABLISHED狀態(tài),服務(wù)端接收到報文后,進入ESTABLISHED狀態(tài)。到此,連接建立完成。
三次握手原因
避免資源被浪費掉。如果在第二步握手時,由于網(wǎng)絡(luò)延遲導致確認包不能及時到達客戶端,那么客戶端會認為第一次握手失敗,再次發(fā)送連接請求,服務(wù)端收到后再次發(fā)送確認包。在這種情況下,服務(wù)端已經(jīng)創(chuàng)建了兩次連接,等待兩個客戶端發(fā)送數(shù)據(jù),而實際卻只有一個客戶端發(fā)送數(shù)據(jù)。
3、TCP斷開連接-四次揮手
四次揮手指客戶端和服務(wù)端各發(fā)送一次請求終止連接的報文,同時雙方響應(yīng)彼此的請求。
四次揮手圖例如下,請配置文字解釋使用哦。
第一次揮手:客戶端發(fā)送FIN=1,seq=x的包給服務(wù)端,表示自己沒有數(shù)據(jù)要進行傳輸,單面連接傳輸要關(guān)閉。發(fā)送完后,客戶端進入
FIN_WAIT_1狀態(tài)。
第二次揮手:服務(wù)端收到請求包后,發(fā)回ACK=1,ack=x+1的確認包,表示確認斷開連接。服務(wù)端進入CLOSE_WAIT狀態(tài)。客戶端收到該包后,進入FIN_WAIT_2狀態(tài)。此時客戶端到服務(wù)端的數(shù)據(jù)連接已斷開。
第三次揮手:服務(wù)端發(fā)送FIN=1,seq=y的包給客戶端,表示自己沒有數(shù)據(jù)要給客戶端了。發(fā)送完后進入LAST_ACK狀態(tài),等待客戶端的確認包。
第四次揮手:客戶端收到請求包后,發(fā)送ACK=1,ack=y+1的確認包給服務(wù)端,并進入TIME_WAIT狀態(tài),有可能要重傳確認包。服務(wù)端收到確認包后,進入CLOSED狀態(tài),服務(wù)端到客戶端的連接已斷開??蛻舳说鹊揭欢螘r間后也會進入CLOSED狀態(tài)。
四次揮手原因
由于TCP的連接是全雙工,雙方都可以主動傳輸數(shù)據(jù),一方的斷開需要告知對方,讓對方可以相關(guān)操作,負責任的表現(xiàn)。
使用TCP協(xié)議有:FTP(文件傳輸協(xié)議)、Telnet(遠程登錄協(xié)議)、SMTP(簡單郵件傳輸協(xié)議)、POP3(和SMTP相對,用于接收郵件)、HTTP協(xié)議等
4、TCP流量控制
滑動窗口協(xié)議
TCP滑動窗口協(xié)議主要為了解決數(shù)據(jù)在網(wǎng)絡(luò)傳輸?shù)倪^程中,發(fā)送方和接收方速率不一致的問題,從而保證數(shù)據(jù)傳輸?shù)目煽啃?,達到流量控制的效果。
發(fā)送方中的數(shù)據(jù)分為三種:
- 發(fā)送已確認
- 發(fā)送未確認
- 未發(fā)送
接收方數(shù)據(jù)分為三種:
- 已接收和確認但未被上層讀取
- 接收未確認
在發(fā)送方的滑動窗口中,可分為發(fā)送窗口和可用窗口。發(fā)送窗口中的數(shù)據(jù)已發(fā)送接收方,但未接到接收方的確認;可用窗口則表示發(fā)送方還可以發(fā)送多少數(shù)據(jù)。發(fā)送方的窗口大小會受到接收方窗口的改變而改變。
利用滑動窗口機制能有效的控制發(fā)送方的發(fā)送數(shù)據(jù)速率。下面是個栗子:
TCP的窗口單位是字節(jié),不是報文端,所以上文假設(shè)一個報文包含100個字節(jié)。ACK是確認位,ack是確認號,seq是序列號,對應(yīng)報文的數(shù)據(jù)格式的。A和B在TCP三次握手時候,B會告訴A自己的接收窗口rwnd大小。上圖中,A向B先發(fā)送了三次數(shù)據(jù),但第三次丟失了,同時受到B的流量控制,當前ack=201,還需允許繼續(xù)發(fā)送序號為201到500共300個字節(jié)。當A發(fā)送到序號為500時,就不能發(fā)新的數(shù)據(jù)了,但能接收第三次丟失的數(shù)據(jù)。
接收方數(shù)據(jù)被上層讀取后,又可以接收序號為501-600共100個字節(jié),所以通知A,接收窗口大小為100,序號為501開頭....在上圖的整個過程中,A共收到B三次流量控制。
TCP報文段發(fā)送的機制
應(yīng)用層把數(shù)據(jù)傳遞給傳輸層的TCP的發(fā)送緩存后,TCP通過不同的機制來控制報文段的發(fā)送時機。
主要有下面三種機制:
- TCP維護一個變量,等于最大報文段長度MSS,緩存中存放的數(shù)據(jù)達到MSS字節(jié)時,則以一個報文段發(fā)送出去。
- 發(fā)送應(yīng)用層指明要求的報文段,即TCP支持的推送操作。
- 發(fā)送法計時器期限到了,就要把前面緩存的數(shù)據(jù)以報文段發(fā)送出去,前提是長度不能超過MSS。
TCP傳輸效率問題
不同的發(fā)送機制都會帶來一定的效率問題,例如用戶發(fā)送一個字符,加上20字節(jié)首部,得到21字節(jié)長的TCP報文段,再加上21字節(jié)的IP首部,就變成41字節(jié)長的IP數(shù)據(jù)報。發(fā)送一個字節(jié),線路上就需要發(fā)送41字節(jié)長的IP數(shù)據(jù)報,若等待接收方確認,線程就又多了40字節(jié)長的數(shù)據(jù)報。所以在線程帶寬不富裕時,這種傳輸效率非常不高。因此應(yīng)當推遲發(fā)回確認報文,并盡量使用捎帶確認的方法。
Negle算法
Negle算法主要為了解決TCP的傳輸效率問題。Negle算法規(guī)定:若要把發(fā)送的數(shù)據(jù)逐個字節(jié)緩存起來,則發(fā)送方需要把第一個字節(jié)發(fā)送出去,然后緩存后面的字節(jié),在收到接收方第一個字節(jié)的確認,再將現(xiàn)有緩存中所有字節(jié)組成一個報文段發(fā)送出去,繼續(xù)緩存后續(xù)數(shù)據(jù)。只有在收到前一個報文的確認之后發(fā)送后面的數(shù)據(jù)。這是為了減少所用帶寬。當發(fā)送數(shù)據(jù)到達TCP發(fā)送窗口的一半或已達到報文段的最大長度也會立即發(fā)送報文段,而不是等待接收方確認。這是為了提高網(wǎng)絡(luò)吞吐量。
糊涂窗口綜合征
TCP接收方的緩存已滿,若上層一次從緩存中讀取一個字節(jié),這樣接收方就可以繼續(xù)接納一個字節(jié)的窗口,然后向發(fā)送方發(fā)送確認,把窗口設(shè)為1個字節(jié)(上文所講,IP數(shù)據(jù)報為41字節(jié)長)。如果這樣持續(xù)下去,那么網(wǎng)絡(luò)效率非常低。
所以有效的解決方法,就是讓接收方等待一定時間,讓緩存空間能夠接納一個最長的報文段,或者等待接收緩存已有一半的空閑空間,再發(fā)出確認報文和通知當前窗口大小。
5、TCP的擁塞控制
擁塞
什么是擁塞呢,在某段時間,若對網(wǎng)絡(luò)中某一資源的需求超過了該資源所能提供的可用部分,網(wǎng)絡(luò)性能就會變壞了,這種情況就叫擁塞。網(wǎng)絡(luò)資源常指網(wǎng)絡(luò)鏈路容量(帶寬)、交換結(jié)點中的緩存和交換處理機。
當出現(xiàn)擁塞,條件允許一般都是通過添加網(wǎng)絡(luò)資源,例如帶寬換成更大的,但這治標不治本,而且不一定總是有用。網(wǎng)絡(luò)擁塞往往是有許多因素引起的,因此就需要擁塞控制了。
擁塞控制
擁塞控制指防止過多的的數(shù)據(jù)注入到網(wǎng)絡(luò)中,這樣可以使網(wǎng)絡(luò)中的路由器或鏈路不過載。擁塞機制是一個全局性的過程,涉及到所有主機、所有路由器,以及與降低網(wǎng)絡(luò)傳輸性能有光的所有因素。
而滑動窗口協(xié)議的流量控制,是指點到點的通信量控制,是端到端的問題。
TCP的擁塞控制方法
TCP進行擁塞控制的算法有四種:慢開始、擁塞避免、快重傳、快恢復(fù)。
擁塞控制是基于擁塞窗口的,發(fā)送方維持一個擁塞窗口 cwnd的狀態(tài)變量。窗口大小取決網(wǎng)絡(luò)的擁塞程度,并且動態(tài)變化,發(fā)送方會讓自己的發(fā)送窗口等于擁塞窗口。判斷網(wǎng)絡(luò)擁塞的依據(jù)就是發(fā)送方接收接收方的確認報文是否超時。
1、慢開始算法
慢開始指主機由小到大逐漸增大發(fā)送窗口,即增大擁塞窗口的數(shù)值。初始擁塞窗口cwnd設(shè)置為不超過2到4個最大報文段SMSS的數(shù)值,具體規(guī)定:
- 若SMSS≤1095字節(jié),cwnd=4 x SMSS字節(jié),不得超過4個報文段。
- 若SMSS>1095且≤2190字節(jié),cwnd=3 X SMSS字節(jié),不得超過3個報文段。
- 若SMSS>2190字節(jié),則 cwnd=2 x SMSS字節(jié),不得超過2個報文段。
從上面的規(guī)定限制了初始擁塞窗口的大小。
慢開始在每收到一個對新的報文段的確認后,cwnd就可以增加最多一個SMSS的數(shù)值。
N是剛收到確認的報文段所確認的字節(jié)數(shù),當N<SMSS時,擁塞窗口每次的增加量要小于SMSS。下文舉例說明慢開始的原理(實際上,TCP的窗口是以字節(jié)大小為單位,下文為了方便以報文端形容):
從圖可知,初始化窗口未1,所有發(fā)送M1報文段,收到確認號之后,發(fā)送M2-M3兩個報文段,因為擁塞窗口增大了,后面的輪次也是這樣翻倍增加的。隨著輪次的增多,那么發(fā)送到網(wǎng)絡(luò)的數(shù)據(jù)就會急劇增加,容易出現(xiàn)擁塞,因此需要慢開始門限(ssthresh)狀態(tài)變量。
- 當cwnd<ssthresh時,使用慢開始算法
- 當cwnd>ssthresh時,使用擁塞避免算法
- 當cwnd=ssthresh時,忙開始或者擁塞避免算法
2、擁塞避免算法
擁塞避免算法就是讓cwnd緩慢增大,每一個輪次把擁cwnd增加1,而不是像慢開始算法那樣翻倍增加。需要注意的是,擁塞避免算法只是讓網(wǎng)絡(luò)不那么快出現(xiàn)擁塞,而不是避免擁塞出現(xiàn)。
上文已經(jīng)說到,判斷網(wǎng)絡(luò)是否擁塞以報文是否超時為準,當網(wǎng)絡(luò)出現(xiàn)擁塞時,會把ssthresh設(shè)為原有的一半,然后開始慢開始算法。如下圖所示:
在上黑色園圈4點的時候,發(fā)送方收到對同一個報文端重復(fù)確認(3-ACK)。這種情況,個別報文端會在網(wǎng)絡(luò)中丟失,但實際上未發(fā)生網(wǎng)絡(luò)擁塞,發(fā)送方未及時收到確認,就會產(chǎn)生超時,誤認為出現(xiàn)擁塞,發(fā)送方會重新開始慢開始算法。減低了傳輸效率。因此,就需要快重傳算法了。
3、 快重傳算法
快重傳算法是讓發(fā)送方今早知道發(fā)生了個別報文段的丟失??熘貍魉惴ㄒ蠼邮辗讲灰却约喊l(fā)送數(shù)據(jù)時才進行捎帶確認,而是立即發(fā)送確認。也就是說,但出現(xiàn)丟包情況,接收方在接收新數(shù)據(jù)時會重復(fù)發(fā)送對丟失包的前一個報文段的確認號。發(fā)送方接收到三次確認號后,就判斷該丟失報文段確實丟失,會立即進行重傳(快重傳)。
4、快恢復(fù)算法
在上文,知道只是報文段丟失,而不是網(wǎng)絡(luò)出現(xiàn)擁塞后,發(fā)送方會調(diào)整ssthresh為原來的一半,然后繼續(xù)進行擁塞避免算法,這個過程就叫快開恢復(fù)算法。
5、小結(jié)
可見,TCP擁塞控制四個算法是相輔相成,少了誰都不行,共同維護這擁塞控制機制。下面是總體的流程圖。
從流量控制和擁塞控制整體看,涉及到三個窗口,接收窗口、發(fā)送窗口、擁塞窗口。發(fā)送窗口的數(shù)值是不能大于接收窗口的,但是擁塞窗口由網(wǎng)絡(luò)的擁塞程度決定的(所以上文的發(fā)送窗口等于擁塞窗口,是假設(shè)在接收窗口數(shù)值足夠大,能夠容納擁塞窗口的數(shù)據(jù))。因此,發(fā)送窗口的上限值應(yīng)該是擁塞窗口cwnd和接收窗口rwnd之間的最小值。也就是說,通過流量控制和擁塞控制,發(fā)送的發(fā)送速率取決于cwnd和rwnd中數(shù)值較小的一個。