面試中有乙個常見問題
tcp建立連線為什麼需要三次握手,兩次握手為什麼不行?
如果對tcp的狀態轉換非常清楚的話,這個問題就很好回答了
這張圖記錄了tcp的所有狀態,而三次握手涉及到的只有圖中的上半部分。
如果只有兩次握手,情況是這樣:
client 傳送 syn
server 傳送 ack + syn
client 收到 server的ack和syn後,進入established 狀態,此時,如果沒有資料需要傳送,會一直什麼也不做,等待資料的到來
而server這邊傳送了ack和syn後,沒有回應,也就無法確認網路是否通暢,但它什麼也做不了,因為即使重發ack和syn,根據兩次握手的規定,它根本得不到任何回應。所以,即使此時server這邊來了資料,也只能等待。
如果client這邊傳送了資料,server這邊才能收到ack,從而進入established狀態,正常收發資料。
雖然一般來說server很少建立連線後直接傳送資料,但tcp協議還是提供了這個功能,怎樣解決呢?
一種很直接的方案就是:讓server回覆ack+syn後直接進入established狀態,不過這樣就有兩個問題:首先這是一種冒險,因為你還不能確認到對方的網路是否通暢,就直接發資料了,有可能會做無用功;其次,就引出這個問題網路上了乙個常見的回答:
防止已失效的連線請求又傳送到伺服器端,因而產生錯誤
這個回答當然是正確的,但我第一次看到這句話並沒有想通,後面對tcp的狀態轉換更加熟悉後才明白,下面來仔細分析一下:
這句話表述的很明確,說的是一種特殊情況,即,client第一次傳送syn1,因為未知原因很慢沒被接收,第二次由於超時重傳發了syn2,被正常接收,此時,第一次的syn1又正常傳送到了server。
在這種情況下,server由於一直處於listen狀態,會建立乙個新的socket,並回覆ack+syn,這個syn是server生成的乙個isn,而client會直接忽略這個包,server會一直處在established 狀態,造成資源的浪費。
而如果是三次握手,server新建立的錯誤連線會不斷重傳ack+syn,但client一直沒有回覆,然後server多次重傳後,就會關閉這個連線,這樣就避免了的資源的浪費。
相比於tcp連線的建立,關閉可能會更加複雜一點。
tcp作為乙個全雙工通訊方式,理想的狀態是滿足一下兩個要求再關閉:
我方的位元組流輸入完畢,向對方傳送了fin,並收到了對方的ack
我方確信對方已經收到了我方的ack
但是在乙個資料有概率丟包的狀態下,想要雙方都完美達成以上兩個要求是不可能的(兩個將軍問題),不過tcp已經大概率可以做到了。
首先在tcp中有一方是可以滿足上面那兩個條件的,哪一方呢?
後傳送fin的一方,因為後傳送的一方中,其fin資料段中也攜帶了ackno,如果收到了這個fin對應的ack,那麼表示對方對這個ackno沒有質疑,而這個ackno正是對之前的fin的ack,所以可以確定對方一定收到了我之前對fin的ack。
所以,後傳送fin的一方只需要收到ack之後就直接關閉了,而先傳送fin的一方,就要多等一會,因為雖然收到了對方的fin,然後回了乙個ack,但是還無法保證對方是否收到了這個ack,多等一會,如果對方重傳了fin,那就再回乙個ack,然後再等一會。這個等一會要等多久呢?
答案是2 * msl,msl全稱是maximum segment lifetime,最長分節生命期。msl是任何ip資料報能夠在網際網路存活的最長時間。為什麼是2倍的msl呢?因為假設我們回覆的ack丟了,對方會先等乙個rtt的時間,這個時間是小於msl的,然後重傳乙個fin,路上在擁堵,也就乙個msl的時間,不然就丟了,所以2 * msl一定是充足的。
等待2msl後,tcp連線就算是正式關閉了。
learning by coding!
一開始我也是看書看部落格,看別人寫三次握手,但是看了感覺會了,過兩天就忘了,而且感覺即使記住了,也是死記硬背的,沒有理解,然後我就下定決心,好好學習一下tcp的狀態圖,而學乙個東西最好的方式有兩步
會用它會造它
用tcp協議當然很簡單,socket等一系列系統呼叫封裝的很好,甚至可以說太好了以至於我們完全感知不到tcp協議做了什麼。因此,自己寫乙個tcp協議當然就是最好的學習方式了,不過我們初學者,全靠自己當然寫不出乙個完整能用的tcp協議了,所以我就上網搜了一下相關的課程實驗,然後就找到了大名鼎鼎的 cs144 ,斯坦福出品,實驗的說明和測試用例都很良心,每當你解決乙個bug,就重新整理了一下你對tcp協議的認知。當你靠自己通過了所有測試用例,我想你已經對tcp的細節都已經非常了解了,再回首看一下tcp協議,頓時有了一種掌控感,當然,這個lab並沒有覆蓋tcp的全部特性,也不要覺得做完了就會對tcp無所不知,但是最複雜最核心的部分已經明白,剩下的也就不是難題了。
tcp三次握手 以及四次揮手
首先client端傳送連線請求報文,server段接受連線後回覆ack報文,並為這次連線分配資源。client端接收到ack報文後也向server段發生ack報文,並分配資源,這樣tcp連線就建立了。那如何斷開連線呢?簡單的過程如下 注意 中斷連線端可以是client端,也可以是server端。假設...
TCP三次握手 四次揮手
tcp 三次握手 tcp 連線是通過三次握手進行初始化的。三次握手的目的是同步連線雙方的序列號和確認號並交換 tcp 視窗大小資訊。以下步驟概述了通常情況下客戶端計算機聯絡伺服器計算機的過程 1.客戶端向伺服器傳送乙個syn置位的tcp報文,其中包含連線的初始序列號x和乙個視窗大小 表示客戶端上用來...
TCP三次握手 四次揮手
服務端的tcp程序先建立傳輸控制塊tcb,準備接受客戶端程序的連線請求,然後服務端程序處於listen狀態,等待客戶端的連線請求,如有,則作出響應。1 客戶端的tcp程序也首先建立傳輸控制模組tcb,然後向服務端發出連線請求報文段,該報文段首部中的syn 1,ack 0,同時選擇乙個初始序號seq ...