計算機網絡 Tcp


TCP連接中的TIME_WAIT狀態
 

一、TIME_WAIT狀態的必要性
上述四次握手描述的是客戶段主動關閉,服務器被動關閉的流程,其一般過程如下:
1、 客戶端發送FIN報文段,進入FIN_WAIT_1狀態。
2、 服務器端收到FIN報文段,發送ACK表示確認,進入CLOSE_WAIT狀態。
3、 客戶端收到FIN的確認報文段,進入FIN_WAIT_2狀態。
4、 服務器端發送FIN報文端,進入LAST_ACK狀態。
5、 客戶端收到FIN報文端,發送FINACK,同時進入TIME_WAIT狀態,啓動TIME_WAIT定時器,超時時間設爲2MSL
6、 服務器端收到FINACK,進入CLOSED狀態。
7、 客戶端在2MSL時間內沒收到對端的任何響應,TIME_WAIT超時,進入CLOSED狀態。
盡最大努力保證四次握手正常關閉

如果不考慮報文延遲、丟失,確認延遲、丟失等情況,TIME_WAIT的確沒有存在的必要。當網絡在不理想的情況下通常會有報文的丟失延遲發生,讓我們看下面的一個特例:
客戶端進入發送收到四次握手關閉的最後一個ACK後,進入TIME_WAIT同時發送ACK,如果其不停留2MSL時間,而是馬上關閉連接,銷燬連接上的資源,當發送如下情況時,將不能正常的完成四次握手關閉:
客戶端發送的ACK在網路上丟失,這樣服務器端收不到最後的ACK,重傳定時器超時,將重傳FIN到客戶端,由於客戶端關於該連接的所有資源都釋放,收到重傳的FIN後,它沒有關於這個FIN的任何信息,所以向服務器端發送一個RST報文端,服務器端收到RST後,認爲搞連接出現了異常(而非正常關閉)。
所以,在TIME_WAIT狀態下等待2MSL時間端,是爲了能夠正確處理第一個ACK(最長生存時間爲MSL)丟失的情況下,能夠收到對端重傳的FIN(最長生存時間爲MSL),然後重傳ACK
是否只要主動關閉方在TIME_WAIT狀態下停留2MSL,四次握手關閉就一定正常完成呢?
答案是否定的?可以考慮如下的情況,
 


TIME_WAIT狀態下發送的ACK丟失,LAST_ACK時刻設定的重傳定時器超時,發送重傳的FIN,很不幸,這個FIN也丟失,主動關閉方在TIME_WAIT狀態等待2MSL沒收到任何報文段,進入CLOSED狀態,當此時被動關閉方並沒有收到最後的ACK。所以即使要主動關閉方在TIME_WAIT狀態下停留2MSL,也不一定表示四次握手關閉就一定正常完成。
結論:在TIME_WAIT下等待2MSL,只是爲了盡最大努力保證四次握手正常關閉。
確保老的報文段在網絡中消失,不會影響新建立的連接

考慮如下的情況,主動關閉方在TIME_WAIT狀態下發送的ACK由於網絡延遲的原因沒有按時到底(但並沒有超過MSL的時間),導致被動關閉方重傳FIN,在FIN重傳後,延遲的ACK到達,被動關閉方進入CLOSED狀態,如果轉動關閉方在TIME_WAIT狀態下發送ACK後馬上進入CLOSED狀態(也就是沒有等待)2MSL時間,則上述的連接已不存在:現在考慮下面的情況,假設上述的鏈接的四元組爲(192.201.0.80:23,192.201.0.85:5555,由於連接已關閉,我們可以馬上建立一個新的連接,並且這個連接的四元組也是(192.201.0.80:23,192.201.0.85:5555),那麼當上一個連接的重傳FIN到達主動關閉方時,被新的連接所接受,這將導致新的連接被複位,很顯然,這不是我們希望看到的事情。
新的連接要建立,必須是在主動關閉方和被動關閉方都進入到CLOSED狀態之後纔有可能。所以,最有可能導致舊的報文段影響新的連接的情況是:
TIME_WAIT狀態之前,主動關閉方發送的報文端在網絡中延遲,但是TIME_WAIT設定爲2MSL時,這些報文端必然會在網絡中消失(最大生存時間爲MSL)。被動關閉方最有可能影響新連接的報文段就是我們上面討論的情況,對方ACK延遲到達,在此之前重傳的FIN,這個報文端發送之後,TIME_WAIT的定時器超時時間肯定大於MSL,在1MSL時間內,這個FIN要麼在網絡中因爲生成時間到達而消失,要麼到達主動關閉方被這確的處理,不會影響新建立的連接。

二、 平靜時間
對於來自某個連接的較早替身的遲到報文段,2MSL等待可以防止將它解釋成爲使用相同插口對的新的連接的一部分。但這隻有在2MSL等待連接中的主機處於正常工作狀態時纔有效。
如果使用處於2MSL等待端口的主機出現故障,它會在MSL秒內重新啓動,並立即使用故障前仍出入2MSL的插口對來建立一個新的連接嗎?如果是這樣,在故障前從這個連接發出而遲到的報文段會被錯誤地當作屬於重啓後新連接的報文端,無論如何重新選擇重啓後新的連接的初始序號,都會發生這種情況。
爲了防止這種情況,RFC 793指出TCP在重啓後的MSL秒內不能建立任何連接。這就是平靜時間quit time)。(有疑問???)


 

我個人理解,在上圖的情況中,也就是TIME_WAIT發送ACK後,主機崩潰,但在ACK到達客戶端時,客戶端的重傳定時器超時,導致重傳FIN,但是重傳之後,延時的ACK到達,此時客戶端進入CLOSED狀態,由於服務器重啓,導致前一連接的所有信息在兩端全部消失。此時新的連接可以在主機重啓後1MSL內建立,假設主機從崩潰到重啓到連接的建立時間很短,1MSL+0.01MSL,那麼重傳的FIN有可能被當作新的連接的報文段。

三、TIME_WAIT、LAST_ACK狀態對收到的報文段的處理 

1. TIME_WAIT收到報文的處理

1)、收到SYN報文段
if (tiflags & TH_SYN &&
    tp->t_state == TCPS_TIME_WAIT &&
    SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {
iss = tp->rcv_nxt + TCP_ISSINCR;
tp = tcp_close(tp);
goto findpcb;
}
TIME_WAIT狀態,如果收到SYN報文段,且新的起始序號大於連接上最後收到的序號,說明對端要求在已被關閉且正處於TIME_WAIT狀態的連接上重新連接。RFC 1122允許這種情況:調用TCP_CLOSE釋放處於TIME_WAIT狀態的原有連接的PCBTCP控制塊。控制跳轉到findpcb,尋找監聽服務器,爲新的連接創建新的插口。

2) 、收到RST報文段
if (tiflags&TH_RST) 
switch (tp->t_state) {
case TCPS_SYN_RECEIVED:
so->so_error = ECONNREFUSED;
goto close;
case TCPS_ESTABLISHED:
case TCPS_FIN_WAIT_1:
case TCPS_FIN_WAIT_2:
case TCPS_CLOSE_WAIT:
so->so_error = ECONNRESET;
close:
tp->t_state = TCPS_CLOSED;
tcpstat.tcps_drops++;
tp = tcp_close(tp);
goto drop;
case TCPS_CLOSING:
case TCPS_LAST_ACK:
case TCPS_TIME_WAIT:
tp = tcp_close(tp);
goto drop;
}
如果在TIME_WAIT狀態收到RST報文段,這釋放連接資源,跳轉到CLOSED狀態,提前終止TIME_WAIT狀態。
如果允許RST終止處於TIME_WAIT狀態的連接,那麼TIME_WAIT狀態也就沒有存在的必要。RFC 1337討論了這一點,及其他取消TIME_WAIT狀態可能的情況,建議不允許RST永久終止處於TIME_WAIT狀態的連接。

3) 收到ACK報文段
此時,連接的兩端已發送過FIN,且兩個FIN都已被確認。但如果TCP對遠端FIN的確認丟失,對端將重傳FIN(帶有ACK)。TCP丟棄報文端並重傳ACK。此外TIME_WAIT定時器必須被重置,時限等於2MSL

4收到FIN報文段
如果在TIME_WAIT狀態收到FIN,說明這是一個重複報文端。啓動TIME_WAIT定時器,時限等於2MSL,發送ACK


2LAST_ACK狀態

1收到RST報文段
如果在TIME_WAIT狀態收到RST報文段,則釋放連接資源,跳轉到CLOSED狀態。
2)收到ACK置位的報文段
case TCPS_LAST_ACK:
if (ourfinisacked) {
tp = tcp_close(tp);
goto drop;
}
break;
如果FIN已確認,連接轉移到CLOSED狀態。tcp_close負責將這一狀態變遷,並同時釋放Interenet PCBTCP控制塊。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章