TCP 和 UDP
作為一個前端已經(jīng)不止一次的在面試中被問到 TCP 和 UDP 協(xié)議了哩治。為了讓自己的回答不那么敷衍,從前端的角度對 TCP 和 UDP 在基礎(chǔ)層面進(jìn)行了一下總結(jié)苍蔬。
TCP 和 UDP 是運輸層的兩種協(xié)議,什么是運輸層呢?
運輸層(Transport Layer)就是負(fù)責(zé)向兩臺主機(jī)進(jìn)程之間的通信提供通用的數(shù)據(jù)傳輸服務(wù),應(yīng)用進(jìn)程利用該服務(wù)傳送應(yīng)用層報文枢贿。
這里的通用是指并不針對某一個特定的網(wǎng)絡(luò)應(yīng)用,而是多種應(yīng)用可以使用同一個運輸層服務(wù)抬吟。
TCP 協(xié)議是一種面向連接的萨咕、可靠的數(shù)據(jù)傳輸服務(wù)统抬』鸨荆可靠指得是通過 TCP 協(xié)議傳送數(shù)據(jù)可以無差錯、不丟失聪建、不重復(fù)钙畔、并且按序到達(dá);
并且 TCP 協(xié)議還具有以下特點:
- 雙方在連接建立之后金麸,都可以在任何時候進(jìn)行數(shù)據(jù)發(fā)送
- 有緩存擎析,發(fā)送和接收時都可以利用緩存臨時存放數(shù)據(jù)
- TCP 是面向字節(jié)流的
UDP 協(xié)議是無連接的、不可靠的。具有以下特點:
- 無連接
- 因為無連接所以不可靠
- UDP 是面向報文的
- 支持 n 對 n 的交互通信
- UDP 無擁塞控制
擁塞控制:
我們知道揍魂,兩臺主機(jī)在傳輸數(shù)據(jù)包的時候桨醋,如果發(fā)送方遲遲沒有收到接收方反饋的ACK,那么發(fā)送方就會認(rèn)為它發(fā)送的數(shù)據(jù)包丟失了现斋,進(jìn)而會重新傳輸這個丟失的數(shù)據(jù)包喜最。然而實際情況有可能此時有太多主機(jī)正在使用信道資源,導(dǎo)致網(wǎng)絡(luò)擁塞了庄蹋,而A發(fā)送的數(shù)據(jù)包被堵在了半路瞬内,遲遲沒有到達(dá)B。這個時候A誤認(rèn)為是發(fā)生了丟包情況限书,會重新傳輸這個數(shù)據(jù)包虫蝶。結(jié)果就是不僅浪費了信道資源,還會使網(wǎng)絡(luò)更加擁塞倦西。因此能真,我們需要進(jìn)行擁塞控制。
由于 UDP 具有無連接扰柠、傳輸速度更快舟陆、效率更高、并且沒有擁塞控制耻矮,所以源主機(jī)發(fā)送速率不受網(wǎng)絡(luò)擁塞的影響秦躯,因此 UDP 協(xié)議被廣泛的應(yīng)用到直播和實時視頻的領(lǐng)域。
與 UDP 相反裆装,TCP 協(xié)議在速度踱承、效率方面沒有優(yōu)勢,但是 TCP 協(xié)議可以很好的保證數(shù)據(jù)傳輸?shù)目煽啃陨诿猓旅鎭砜纯?TCP 是如何做到可靠的茎活。
- 校驗:如果接收端校驗出包有錯,則進(jìn)行丟棄且不進(jìn)行響應(yīng)
- 排序:在將數(shù)據(jù)包交給應(yīng)用層之前琢唾,TCP 協(xié)議會保證數(shù)據(jù)包的有序性
- 去重:丟棄重復(fù)的數(shù)據(jù)
- 應(yīng)答:接收方接收到數(shù)據(jù)后载荔,將發(fā)送確認(rèn)信息給發(fā)送方
- 超時重發(fā):當(dāng)發(fā)送方發(fā)出數(shù)據(jù)后,會啟動一個定時器采桃,當(dāng)超過定時器時限后懒熙,會重新發(fā)這個報文段
- 流量控制:利用固定大小的緩沖空間防止接收方緩沖區(qū)溢出
三次握手
我想不管你了不了解這些協(xié)議,你都會聽說過三次握手普办。
我們把客戶端和服務(wù)器每一次交互都比喻成一次握手工扎,那么簡單來說,當(dāng)建立一個 TCP 連接的時候衔蹲,整個過程需要客戶端和服務(wù)端交互三個包肢娘,交互這些包的目的是連接服務(wù)器指定端口,建立 TCP 連接,并同步連接雙方的序列號和確認(rèn)號以及交換 TCP 窗口大小橱健。
第一次握手
開始建立連接時而钞,客戶端向服務(wù)器發(fā)出連接請求報文,報文首部中的同部位 SYN = 1拘荡,同時選擇一個初始序列號 seq = x 笨忌,
此時客戶端進(jìn)程進(jìn)入了 SYN-SENT (同步已發(fā)送狀態(tài))狀態(tài),等待服務(wù)器確認(rèn)俱病。
第二次握手
服務(wù)器收到 syn 包后官疲,如果同意連接,則發(fā)出確認(rèn)報文亮隙;確認(rèn)報文 ACK = 1途凫,SYN = 1,確認(rèn)號是 ack = x + 1溢吻,同時也要為自己初始化一個序列號 seq = y出革,
此時服務(wù)器進(jìn)程進(jìn)入了 SYN-RCVD(同步收到)狀態(tài)姐刁。
第三次握手
客戶端收到服務(wù)器的 SYN + ACK 包,要向服務(wù)器給出確認(rèn)。確認(rèn)報文的 ACK = 1膝宁,ack = y + 1碍论,自己的序列號 seq = x + 1透敌。此時抗果,TCP 連接建立,
此時客戶端進(jìn)入 ESTABLISHED (已建立連接)狀態(tài)迅耘。
四次揮手
當(dāng)斷開連接時的四次揮手
第一次揮手:
客戶端進(jìn)程發(fā)出連接釋放報文贱枣,并且停止發(fā)送數(shù)據(jù)。此時颤专,客戶端進(jìn)入 FIN-WAIT-1(終止等待 1)狀態(tài)纽哥。
第二次揮手:
服務(wù)器收到連接釋放報文,發(fā)出確認(rèn)報文栖秕,此時春塌,服務(wù)端就進(jìn)入了 CLOSE-WAIT(關(guān)閉等待)狀態(tài)。
第三次揮手:
服務(wù)器將最后的數(shù)據(jù)發(fā)送完畢后簇捍,就向客戶端發(fā)送連接中斷報文只壳,此時,服務(wù)器就進(jìn)入了 LAST-ACK(最后確認(rèn))狀態(tài)垦写,等待客戶端的確認(rèn)吕世。
第四次揮手:
客戶端收到服務(wù)器的連接釋放報文后彰触,必須發(fā)出確認(rèn)梯投,客戶端就進(jìn)入了 TIME-WAIT(時間等待)狀態(tài)。
最后服務(wù)器只要收到了客戶端發(fā)出的確認(rèn),立即進(jìn)入 CLOSED 狀態(tài)分蓖。就結(jié)束了這次的 TCP 連接
了解了整個建立和斷開連接的過程尔艇,思考幾個問題:
1.TCP 建立連接為什么需要三次握手,一次握手行不行么鹤?
答案是當(dāng)然不行终娃,為什么不能一次握手:因為 TCP 是面向連接的,一次握手蒸甜,只發(fā)一條信息出去棠耕,沒有任何回信肯定無法建立連接。
2.兩次握手是否可行柠新?
假設(shè)只有兩次握手窍荧,當(dāng) A(客戶端) 想要建立連接時發(fā)送一個 SYN ,然后等待 ACK 恨憎,結(jié)果這個 SYN 因為網(wǎng)絡(luò)問題沒有及時到達(dá) B(服務(wù)端)蕊退,所以 A 在一段時間內(nèi)沒收到 ACK 后,會再發(fā)送一個 SYN 憔恳,這次 B 成功收到瓤荔,并向 A 發(fā)送了 ACK ,然后 A 也收到 ACK 钥组,但是此時 A 發(fā)送的第一個 SYN 終于到了 B输硝,對于 B 來說這是一個新連接請求,然后 B 又為這個連接申請資源程梦,返回 ACK 腔丧,然而這個 SYN 是個無效的請求,A 收到這個 SYN 的 ACK 后也并不會理會它作烟,而 B 卻不知道愉粤,B 會一直為這個連接維持著資源,造成資源的浪費拿撩。
3.那為什么三次握手就可以解決這些問題衣厘?
兩次握手的問題在于服務(wù)器端不知道一個 SYN 是否是無效的,而三次握手機(jī)制因為客戶端會給服務(wù)器回復(fù)第二次握手压恒,也意味著服務(wù)器會等待客戶端的第三次握手影暴,如果第三次握手遲遲不來,在嘗試重發(fā)后仍未收到探赫,服務(wù)器便會認(rèn)為這個 SYN 是無效的型宙,釋放相關(guān)資源。但這時有個問題就是客戶端完成第二次握手便認(rèn)為連接已建立伦吠,而第三次握手可能在傳輸中丟失妆兑,服務(wù)端會認(rèn)為連接是無效的魂拦,這時如果客戶端向服務(wù)端寫數(shù)據(jù),服務(wù)端將以 RST 包響應(yīng)搁嗓,客戶端就可以感知到錯誤芯勘。
4.如果第三次握手失敗怎么辦?
與第三題類似腺逛,當(dāng)客戶端收到服務(wù)端的 SYN+ACK 應(yīng)答后荷愕,其狀態(tài)變?yōu)?ESTABLISHED,并會發(fā)送 ACK 包給服務(wù)端棍矛,準(zhǔn)備發(fā)送數(shù)據(jù)了安疗。如果此時 ACK 在網(wǎng)絡(luò)中丟失,過了超時計時器后够委,那么Server端會重新發(fā)送 SYN+ACK 包茂契,默認(rèn)是5次。如果重傳指定次數(shù)到了后慨绳,仍然未收到 ACK 應(yīng)答掉冶,那么一段時間后,服務(wù)端自動關(guān)閉這個連接脐雪。但是客戶端認(rèn)為這個連接已經(jīng)建立厌小,如果客戶端端向服務(wù)端寫數(shù)據(jù),服務(wù)端端將以 RST 包響應(yīng)战秋,客戶端就可以感知到錯誤璧亚。