滴滴-測試開發(fā)面經(jīng)(六)
點(diǎn)擊藍(lán)字關(guān)注我們,獲取更多面經(jīng)



最初,客戶機(jī)A與服務(wù)器B的TCP進(jìn)程都處于 CLOSED 狀態(tài)。
然后由服務(wù)器B先創(chuàng)建TCB(傳輸控制塊),進(jìn)入到 LISTEN 狀態(tài),準(zhǔn)備隨時響應(yīng)客戶請求

下面開始三握:
第一次握手
A的TCP進(jìn)程創(chuàng)建TCB(傳輸控制塊),然后向B發(fā)出連接請求報文段。段首部中的 同步位SYN=1,同時選擇一個初始序列號seq=x;(SYN報文段不能攜帶數(shù)據(jù),但需要消耗一個序列號)這時客戶端A進(jìn)入到 SYN-SENT(同步已發(fā)送)狀態(tài)。
第二次握手
B收到連接請求報文段,如果同意建立連接,則向A發(fā)送確認(rèn)。在確認(rèn)報文段中 同步位SYN=1、確認(rèn)位ACK=1、確認(rèn)號ack=x+1(對接收的序列號seq=x的報文段進(jìn)行確認(rèn),并期望接收的下一個報文段的序號seq=x+1),同時也為自己選擇一個初始序列號seq=y,這時服務(wù)器B進(jìn)入 SYN-RCVID 狀態(tài)。
注:該報文段是ACK報文段的同時也是SYN報文段,所以該報文段也不能攜帶數(shù)據(jù)。
第三次握手
A收到B的確認(rèn)以后,再向B發(fā)出確認(rèn)。確認(rèn)報文 ACK=1、確認(rèn)號ack=y+1(對接收的序列號seq=y的報文段進(jìn)行確認(rèn),并期望接收的下一個報文段的序號seq=y+1)。這時A進(jìn)入到 ESTAB-LISHED 狀態(tài)。當(dāng)B接收到A的確認(rèn)后,也進(jìn)入 ESTAB-LISHED 狀態(tài)。連接建立完成
注:ACK報文段可以攜帶數(shù)據(jù),但如果不攜帶數(shù)據(jù)則不消耗序列號,在這種情況下,下一個報文段的序號不變,seq仍是x+1。
下面對 同步位SYN、確認(rèn)位ACK、確認(rèn)號ack 以及 三次握手時出現(xiàn)的五個狀態(tài) 進(jìn)行下解釋
同步位SYN:在建立連接時用來同步序號;當(dāng)SYN=1,ACK=0時,表明這是一個連接請求報文段。當(dāng)SYN=1,ACK=1時,表明這是一個連接接收報文段;
確認(rèn)位ACK:當(dāng)ACK=1時,確認(rèn)號ack才生效。在請求建立連接后(第一次握手后),所有的報文段都必須把ACK置1。
確認(rèn)號ack:期望收到的下一個報文段的第一個數(shù)據(jù)字節(jié)的序號,比如:B正確接收到了A發(fā)送過來的一個報文段,序號是501,數(shù)據(jù)長度是200字節(jié);這表明B正確接收到了序號501-700的數(shù)據(jù)。所以,B期望的下一個序號是701,于是B在發(fā)送給A的確認(rèn)報文段中確認(rèn)號ack=701。
CLOSED:初始關(guān)閉狀態(tài)
LISTEN:監(jiān)聽狀態(tài),等待客戶連接
SYB-SENT:同步已發(fā)送
SYN-RCVD:同步已接收
ESTAB-LISHED:已建立連接
為什么不是兩次握手?
這主要是為了防止已失效的連接請求報文段突然又傳送到了 B,從而造成資源浪費(fèi)。
考慮一種異常情況,即 A 發(fā)出的第一個連接請求報文段并沒有丟失,而是在某些網(wǎng)絡(luò)結(jié)點(diǎn)長時間的滯留了,以致延誤到連接釋放以后的某個時間才到達(dá) B。本來這是一個早已失效的報文段,但 B 收到此失效的連接請求報文段后,就誤認(rèn)為是 A 又發(fā)出了一次新的連接請求,于是就向 A 發(fā)出確認(rèn)報文段,同意建立連接。假定不采用報文握手,那么只要 B 發(fā)出確認(rèn),新的連接就建立了。
由于現(xiàn)在 A 并沒有發(fā)出建立連接的請求,因此不會理睬 B 的確認(rèn),也不會向 B 發(fā)送數(shù)據(jù),但 B 卻認(rèn)為新的運(yùn)輸連接已經(jīng)建立了,并一直等待 A 發(fā)來數(shù)據(jù),B 的許多資源就這樣浪費(fèi)了。
采用三次握手的辦法,可以防止上述現(xiàn)象的發(fā)生,例如在剛才的異常情況下,A 不會向 B 的確認(rèn)發(fā)出確認(rèn),B 由于收不到確認(rèn),就知道 A 并沒有要求建立連接。
為什么不是四次握手?
完全可靠的通信協(xié)議是根本不存在的,我們?nèi)魏蔚耐ㄐ艆f(xié)議都是在接受這樣的現(xiàn)實(shí)情況之上進(jìn)行的。 三次握手后,A 和 B 至少可以確認(rèn)之前的通信情況,但無法確認(rèn)之后的情況。在這個道理上說,無論是四次還是五次或是更多次都是徒勞的。
A與B想要斷開連接,需要經(jīng)過四次揮手

第一次揮手:A先發(fā)送連接釋放報文段,段首部的終止控制位FIN=1,序號seq=u(等于A前面發(fā)送數(shù)據(jù)的最后一個序號加1);然后A進(jìn)入 FIN-WAIT-1(終止等待1)狀態(tài),等待B的確認(rèn)。A
注:FIN報文段即使不攜帶數(shù)據(jù)也要消耗一個序列。
第二次揮手:B收到A的連接釋放報文段后,立刻發(fā)出確認(rèn)報文段,確認(rèn)號ack=u+1,序號seq=v(等于B前面發(fā)送數(shù)據(jù)的最后一個序號加1);然后B進(jìn)入CLOSE-WAIT(關(guān)閉等待)狀態(tài)。
注:TCP服務(wù)器這時會通知高層應(yīng)用進(jìn)程,從A到B這個方向的連接就斷開了,這時TCP連接處于半關(guān)閉(half-close)狀態(tài);但B到A這個方向的連接并沒有斷,B仍然可以向A發(fā)送數(shù)據(jù)。
第三次揮手:A收到B的確認(rèn)報文段后進(jìn)入到 FIN-WAIT-2(終止等待2)狀態(tài),繼續(xù)等待B發(fā)出連接釋放報文段;若B已經(jīng)沒有數(shù)據(jù)要發(fā)送,B就會向A發(fā)送連接釋放報文段,段首部的終止控制位 FIN=1,序號seq=w(半關(guān)閉狀態(tài)可能又發(fā)送了一些數(shù)據(jù)),確認(rèn)號ack=u+1,這時B進(jìn)入LAST-ACK(最后確認(rèn))狀態(tài),等待A的確認(rèn)。
特別注意:確認(rèn)號ack沒有變,仍然為上次發(fā)送過的確認(rèn)號u+1。
第四次揮手:A收到B的連接釋放報文段并發(fā)出確認(rèn),確認(rèn)段中 確認(rèn)位ACK=1,確認(rèn)號ack=w+1,序號seq=u+1;然后A進(jìn)入到TIME-WAIT(時間等待)狀態(tài)。當(dāng)B再接收到該確認(rèn)段后,B就進(jìn)入CLOSED狀態(tài)。
注:處于TIME-WAIT狀態(tài)的A必須等待2MSL時間后,才會進(jìn)入CLOSED狀態(tài)。MSL(Maximum Segment Lifetime)最長報文段壽命,RFC 793 建議設(shè)為兩分鐘,對于現(xiàn)在的網(wǎng)絡(luò),MSL=2分鐘可能太長了一些,我們可根據(jù)具體情況使用更小的MSL值。
四揮的七個狀態(tài):
ESTAB-LISHED:已建立連接
FIN-WAIT-1:終止等待1
CLOSE-WAIT:關(guān)閉等待
FIN-WAIT-2:終止等待2
LAST-ACK:最后確認(rèn)
TIME-WAIT:時間等待
CLOSED:關(guān)閉
為什么A要等待2MSL的時間?
為了保證A發(fā)送的最后一個報文段能夠到達(dá)B。因?yàn)檫@個 ACK 有可能丟失,從而導(dǎo)致處在 LAST-ACK 狀態(tài)的服務(wù)器收不到對 FIN-ACK 的確認(rèn)報文。服務(wù)器會超時重傳這個 FIN-ACK,接著客戶端再重傳一次確認(rèn),重新啟動時間等待計(jì)時器。最后客戶端和服務(wù)器都能正常的關(guān)閉。假設(shè)客戶端不等待 2MSL,而是在發(fā)送完 ACK 之后直接釋放關(guān)閉,一旦這個 ACK 丟失的話,服務(wù)器就無法正常的進(jìn)入關(guān)閉連接狀態(tài)。
可以防止已失效的報文段。客戶端在發(fā)送最后一個 ACK 之后,再經(jīng)過經(jīng)過 2MSL,就可以使本連接持續(xù)時間內(nèi)所產(chǎn)生的所有報文段都從網(wǎng)絡(luò)中消失,從保證在關(guān)閉連接后,不會有仍在網(wǎng)絡(luò)中滯留的報文段去騷擾服務(wù)器。
linux服務(wù)器出現(xiàn)大量 TIME-WAIT 狀態(tài)的TCP連接 的處理方法
通過調(diào)整內(nèi)核參數(shù)解決,
vi /etc/sysctl.conf
編輯文件,加入以下內(nèi)容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然后執(zhí)行 /sbin/sysctl -p 讓參數(shù)生效。
net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies。當(dāng)出現(xiàn)SYN等待隊(duì)列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認(rèn)為0,表示關(guān)閉;
net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將 TIME-WAIT sockets重新用于新的TCP連接,默認(rèn)為0,表示關(guān)閉;
net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中 TIME-WAIT sockets的快速回收,默認(rèn)為0,表示關(guān)閉。
net.ipv4.tcp_fin_timeout 修改系統(tǒng)默認(rèn)的 TIMEOUT 時間。
為什么要四次揮手?
A 向 B 發(fā)送一個連接釋放請求報文,代表 A 的數(shù)據(jù)傳送完了,請求釋放連接;
B 收到后,B 立即向 A 發(fā)送一個確認(rèn)報文,代表 B 已經(jīng)知道 A 沒有數(shù)據(jù)要傳送了,但是 B 可能還有數(shù)據(jù)要向 A 傳送;
B 的數(shù)據(jù)傳送完后,向 A 發(fā)送一個連接釋放請求報文,代表 B 的數(shù)據(jù)也傳送完了,請求釋放連接;
A 收到后,也立即向 B 發(fā)送一個確認(rèn)報文,同時等待 2MSL 后,連接斷開。
注:TCP 是全雙工通信,因此必須兩個方向分別斷開連接。
為什么建立連接三次,斷開連接四次?
因?yàn)榻⑦B接時,服務(wù)器的確認(rèn) ACK 和請求同步 SYN 可以放在一個報文里,而斷開連接時,服務(wù)器可能還有數(shù)據(jù)要傳送,因此,必須先發(fā)一個客戶端斷開連接請求的確認(rèn) ACK,以免客戶端超時重傳,待服務(wù)器的數(shù)據(jù)傳送完畢后,再發(fā)送一個請求斷開連接的報文段。
斷開時次數(shù)比連接多一次,是因?yàn)檫B接過程,通信只需要處理「連接」,而斷開過程,通信需要處理「數(shù)據(jù)+連接」。
更多面經(jīng)
掃描二維碼
獲取更多面經(jīng)
扶搖就業(yè)
