1. 程式人生 > >【搞定網路協議】面試題整理

【搞定網路協議】面試題整理

本文記錄面試中經常問到的與網路協議相關的面試題。持續更新.......

先搭個模組架子,後面慢慢記錄!

 

三次握手

TCP報文段首部格式:

序號:本報文段所傳送的資料的第一個位元組的序號;

確認號ack期待收到對方下一個報文段的第一個資料位元組的序號;

確認ACK:佔1位,僅當ACK=1時,確認號欄位才有效。ACK=0時,確認號無效;

同步SYN:連線建立時用於同步序號。當SYN=1,ACK=0時表示:這是一個連線請求報文段;

                  若同意連線,則在響應報文段中使得SYN=1,ACK=1。因此,SYN=1表示這是一個連線請求,或連線接受報文;

終止FIN:用來釋放一個連線。FIN=1表示:此報文段的傳送方的資料已經發送完畢,並要求釋放運輸連線。

TCP建立連線的過程叫做握手,握手需要在客戶和伺服器之間交換三個TCP報文段。

最初客戶端和服務端都處於CLOSED(關閉)狀態。本例中A主動開啟連線,B被動開啟連線。

一開始,B的TCP伺服器程序首先建立傳輸控制塊TCB,準備接受客戶端程序的連線請求。然後服務端程序就處於LISTEN(監聽)狀態,等待客戶端的連線請求。如有,立即作出響應。

A的TCP客戶端程序也是首先建立傳輸控制塊TCB。然後,在打算建立TCP連線時,向B發出連線請求報文段,這時首部中的同步位SYN=1,同時選擇一個初始序號seq=x。TCP規定,SYN報文段(即SYN=1的報文段)不能攜帶資料,但要消耗掉一個序號。這時,TCP客戶程序進入SYN-SENT(同步已傳送)狀態

B收到連線請求報文後,如果同意建立連線,則向A傳送確認。在確認報文段中應把SYN位和ACK位都置1,確認號是ack = x + 1,同時也為自己選擇一個初始序號seq = y。請注意,這個報文段也不能攜帶資料,但同樣要消耗掉一個序號。這時TCP服務端程序進入SYN-RCVD(同步收到)狀態

TCP客戶程序收到B的確認後,還要向B給出確認。確認報文段的ACK置1,確認號ack = y +  1,而自己的序號seq = x + 1。這時ACK報文段可以攜帶資料。但如果不攜帶資料則不消耗序號,這種情況下,下一個資料報文段的序號仍是seq = x + 1。這時,TCP連線已經建立,A進入ESTABLISHED(已建立連線)狀態

為什麼是三次握手,而不是兩次握手或者四次握手呢?

不可以兩次握手的原因:

為了防止已經失效的連結請求報文段突然又傳送到了B,因而產生錯誤。比如下面這種情況:A發出的第一個連線請求報文段並沒有丟失,而是在網路結點長時間滯留了,以致於延誤到連線釋放以後的某個時間段才到達B。本來這是一個早已失效的報文段。但是B收到此失效的連結請求報文段後,就誤認為A又發出一次新的連線請求。於是就向A發出確認報文段,同意建立連線。

對於上面這種情況,如果不進行第三次握手,B發出確認後就認為新的運輸連線已經建立了,並一直等待A發來資料。B的許多資源就這樣白白浪費了。

如果採用了三次握手,由於A實際上並沒有發出建立連線請求,所以不會理睬B的確認,也不會向B傳送資料。B由於收不到確認,就知道A並沒有要求建立連線。

不需要四次握手的原因:

有人可能會說A發出第三次握手的資訊後在沒有接收到B的請求就已經進入了連線狀態,那如果A的這個確認包丟失或者滯留了怎麼辦?

我們需要明白一點,完全可靠的通訊協議是不存在的。在經過三次握手之後,客戶端和服務端已經可以確認之前的通訊狀況,都收到了確認資訊。所以即便再增加握手次數也不能保證後面的通訊完全可靠,所以是沒有必要的。


四次揮手

資料傳輸結束後,通訊的雙方都可以釋放連線。現在A和B都處於ESTABLISHED狀態

A的應用程序先向其TCP發出連線釋放報文段,並停止再發送資料,主動關閉TCP連線。A把連線釋放報文段首部的終止控制位FIN置1,其序號aeq = u(等於前面已傳送過的資料的最後一個位元組的序號加1),這時A進入FIN-WAIT-1(終止等待1)狀態,等待B的確認。請注意:TCP規定,FIN報文段即使不攜帶資料,也將消耗掉一個序號。

B收到連線釋放報文段後立即發出確認,確認號是ack = u + 1,而這個報文段自己的序號是v(等於B前面已經傳送過的資料的最後一個位元組的序號加1).然後B就進入CLOSE-WAIT(關閉等待)狀態。TCP服務端程序這時應通知高層應用程序,因而從A到B這個方向的連線就釋放了,這時的TCP連線處於半關閉(half-close)狀態,即A已經沒有資料要傳送了,但B若傳送資料,A仍要接收。也就是說,從B到A這個方向的連線並未關閉,這個狀態可能會持續一段時間。

A收到來自B的確認後,就進入FIN-WAIT-2(終止等待2)狀態,等待B發出的連線釋放報文段。

若B已經沒有要向A傳送的資料,其應用程序就通知TCP釋放連線。這時B發出的連線釋放報文段必須使FIN=1。假定B的序號為w(在半關閉狀態,B可能又傳送了一些資料)。B還必須重複上次已傳送過的確認號ack = u + 1。這時B就進入LAST-ACK(最後確認)狀態,等待A的確認。

A在收到B的連線釋放報文後,必須對此發出確認。在確認報文段中把ACK置1,確認號ack = w + 1,而自己的序號seq = u + 1(前面傳送的FIN報文段要消耗一個序號)。然後進入TIME-WAIT(時間等待)狀態。請注意,現在TCP連線還沒有釋放掉。必須經過時間等待計時器設定的時間2MSL(MSL:最長報文段壽命)後,A才能進入到CLOSED狀態,然後撤銷傳輸控制塊,結束這次TCP連線。當然如果B一收到A的確認就進入CLOSED狀態,然後撤銷傳輸控制塊。所以在釋放連線時,B結束TCP連線的時間要早於A。

為什麼A在TIME-WAIT狀態必須等待2MSL的時間呢?

1、為了保證A傳送的最後一個ACK報文段能夠到達B。這個ACK報文段有可能丟失,因而使處在LAST-ACK狀態的B收不到對已傳送的FIN+ACK報文段的確認。B會超時重傳這個FIN+ACK報文段,而A就能在2MSL時間內收到這個重傳的FIN+ACK報文段。接著A重傳一次確認,重新啟動2MSL計時器。最後,A和B都正常進入到CLOSED狀態。如果A在TIME-WAIT狀態不等待一段時間,而是在傳送完ACK報文段後立即釋放連線,那麼就無法收到B重傳的FIN+ACK報文段,因而也不會再發送一次確認報文段,這樣,B就無法按照正常步驟進入CLOSED狀態。

2、防止已失效的連線請求報文段出現在本連線中。A在傳送完最後一個ACK報文段後,再經過時間2MSL,就可以使本連線持續的時間內所產生的所有報文段都從網路中消失。這樣就可以使下一個連線中不會出現這種舊的連線請求報文段。

保活計時器:

除時間等待計時器外,TCP還有一個保活計時器(keepalive  timer)。設想這樣的場景:客戶已主動與伺服器建立了TCP連線。但後來客戶端的主機突然發生故障。顯然,伺服器以後就不能再收到客戶端發來的資料。因此,應當有措施使伺服器不要再白白等待下去。這就需要使用保活計時器了。

伺服器每收到一次客戶的資料,就重新設定保活計時器,時間的設定通常是兩個小時。若兩個小時都沒有收到客戶端的資料,服務端就傳送一個探測報文段,以後則每隔75秒鐘傳送一次。若連續傳送10個探測報文段後仍然無客戶端的響應,服務端就認為客戶端出了故障,接著就關閉這個連線。