TCP的整個(gè)連接過程
如果沒有基礎(chǔ)的話,直接看這張圖或者網(wǎng)絡(luò)上各種文字描述,十分生澀,所以先看懂接下來的握手揮手的圖,理解之后,再看這個(gè)有限狀態(tài)機(jī)就感覺原來如此簡單。
三次握手
握手過程
第一次握手:主機(jī)A發(fā)送位碼為syn=1,隨機(jī)產(chǎn)生seq
number=x的數(shù)據(jù)包到服務(wù)器,客戶端進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器的確認(rèn);主機(jī)B由SYN=1知道A要求建立連接。
第二次握手:主機(jī)B收到請求后要確認(rèn)連接信息,向A發(fā)送ack
number(主機(jī)A的seq+1)、syn=1、ack=1,隨機(jī)產(chǎn)生seq=y的包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài)。
第三次握手:主機(jī)A收到后檢查ack number是否正確,即第一次發(fā)送的seq number+1,以及位碼ack是否為1,若正確,主機(jī)A會(huì)再發(fā)送ack
number(主機(jī)B的seq+1)、ack=1,主機(jī)B收到后確認(rèn)seq值與ack=1則連接建立成功??蛻舳撕头?wù)器端都進(jìn)入ESTABLISHED狀態(tài)。
三次握手的必要性
* 第一次握手:客戶端發(fā)送網(wǎng)絡(luò)包,服務(wù)端收到了。這樣服務(wù)端就能得出結(jié)論:客戶端的發(fā)送能力、服務(wù)端的接收能力是正常的。
*
第二次握手:服務(wù)端發(fā)包,客戶端收到了。這樣客戶端就能得出結(jié)論:服務(wù)端的接收、發(fā)送能力,客戶端的接收、發(fā)送能力是正常的。不過此時(shí)服務(wù)器并不能確認(rèn)客戶端的接收能力是否正常。
* 第三次握手:客戶端發(fā)包,服務(wù)端收到了。這樣服務(wù)端就能得出結(jié)論:客戶端的接收能力,服務(wù)器自己的發(fā)送能力也正常。
至此,客戶端和服務(wù)端可以確定雙方的接收和發(fā)送能力均正常。
第三次握手的必要性
這主要是為了防止已失效的連接請求報(bào)文段突然又傳送到了服務(wù)器端,從而減少服務(wù)端的開銷。
如果只有兩次握手就建立連接會(huì)出現(xiàn)這種情況:客戶端發(fā)出的連接請求報(bào)文段在某些網(wǎng)絡(luò)節(jié)點(diǎn)長時(shí)間滯留了,以致延誤到連接釋放以后的某個(gè)時(shí)間才能到達(dá)服務(wù)端。本來這是一個(gè)早已失效的報(bào)文段,但服務(wù)端收到此失效的連接請求報(bào)文段后,就誤認(rèn)為客戶端又發(fā)出了一次新的連接請求。于是向客戶端發(fā)出確認(rèn)報(bào)文段,同意建立連接。由于現(xiàn)在客戶端并沒有發(fā)出建立連接的請求,因此不會(huì)處理服務(wù)端的確認(rèn),也不會(huì)向服務(wù)端發(fā)送數(shù)據(jù)。但服務(wù)端卻以為新的連接已經(jīng)建立了,并一直等待客戶端發(fā)來數(shù)據(jù)。
服務(wù)端會(huì)因此浪費(fèi)很多了。
如果第三次握手丟失了,客戶端服務(wù)端會(huì)如何處理?
服務(wù)端:
該TCP連接的狀態(tài)為SYN_RECV,并且會(huì)根據(jù)TCP的超時(shí)重傳機(jī)制,會(huì)等待3秒、6秒、12秒后重新發(fā)送SYN+ACK包,以便Client重新發(fā)送ACK包。而Server重發(fā)SYN+ACK包的次數(shù),可以通過設(shè)置/proc/sys/net/ipv4/tcp_synack_retries修改,默認(rèn)值為5。如果重發(fā)指定次數(shù)之后,仍然未收到客戶端的ACK應(yīng)答,那么一段時(shí)間后,服務(wù)端自動(dòng)關(guān)閉這個(gè)連接。
客戶端:
客戶端在接收到SYN+ACK包,它的TCP連接狀態(tài)就為ESTABLISHED(已連接),表示該連接已經(jīng)建立。那么如果第三次握手中的ACK包丟失的情況下,客戶端向服務(wù)端發(fā)送數(shù)據(jù),服務(wù)端將以RST包(reset重置)響應(yīng),才能感知到服務(wù)端的錯(cuò)誤。
什么是syn flood攻擊
syn
flood是一種經(jīng)典的ddos攻擊手段,這里面用到了TCP三次握手存在的漏洞。當(dāng)服務(wù)端接收到SYN后進(jìn)入SYN-RECV狀態(tài),此時(shí)的連接稱為半連接,同時(shí)會(huì)被服務(wù)端寫入一個(gè)半連接隊(duì)列。如果攻擊者在短時(shí)間內(nèi)不斷的向服務(wù)端發(fā)送大量的SYN包而不響應(yīng),那么服務(wù)器的半連接隊(duì)列很快會(huì)被寫滿,從而導(dǎo)致無法工作。
實(shí)現(xiàn)syn flood
的手段,可以通過偽造源IP的方式,這樣服務(wù)器的響應(yīng)就永遠(yuǎn)到達(dá)不了客戶端(握手無法完成);當(dāng)然,通過設(shè)定客戶端防火墻規(guī)則也可以達(dá)到同樣的目的。對(duì)syn
flood實(shí)現(xiàn)攔截是比較困難的,可以通過啟用 syn_cookies
的方式實(shí)現(xiàn)緩解,但這通常不是最佳方案。最好的辦法是通過專業(yè)的防火墻來解決,基本上所有的云計(jì)算大 都具備這個(gè)能力。
四次揮手
揮手過程
第一次揮手:主機(jī)A(可以是客戶端,也可以是服務(wù)器端),設(shè)置Sequence Number和Acknowledgment
Number,向主機(jī)B發(fā)送一個(gè)FIN報(bào)文段;此時(shí),主機(jī)A進(jìn)入FIN_WAIT_1狀態(tài);這表示主機(jī)A沒有數(shù)據(jù)要發(fā)送給主機(jī)B了。
第二次揮手:主機(jī)B收到了主機(jī)A發(fā)送的FIN報(bào)文段,向主機(jī)A回一個(gè)ACK報(bào)文段,Acknowledgment Number為Sequence
Number加1,主機(jī)A進(jìn)入FIN_WAIT_2狀態(tài);主機(jī)B告訴主機(jī)A,我也沒有數(shù)據(jù)要發(fā)送了,可以進(jìn)行關(guān)閉連接了。
第三次揮手:主機(jī)B向主機(jī)A發(fā)送FIN報(bào)文段,請求關(guān)閉連接,同時(shí)主機(jī)B進(jìn)入CLOSE_WAIT狀態(tài)。
第四次揮手:主機(jī)A收到主機(jī)B發(fā)送的FIN報(bào)文段,向主機(jī)B發(fā)送ACK報(bào)文段,然后主機(jī)A進(jìn)入TIME_WAIT狀態(tài);主機(jī)B收到主機(jī)A的ACK報(bào)文段以后,就關(guān)閉連接;此時(shí),主機(jī)A等待2MSL后依然沒有收到回復(fù),則證明主機(jī)B已正常關(guān)閉,那好,主機(jī)A也可以關(guān)閉連接了。
主機(jī)B發(fā)送了FIN-ACK之后,會(huì)立即啟動(dòng)超時(shí)重傳計(jì)時(shí)器
主機(jī)A在發(fā)送最后一個(gè)ACK之后,會(huì)立即啟動(dòng)時(shí)間等待計(jì)時(shí)器
揮手為什么需要四次?
因?yàn)楫?dāng)服務(wù)端收到客戶端的SYN連接請求報(bào)文后,可以直接發(fā)送SYN+ACK報(bào)文。其中ACK報(bào)文是用來應(yīng)答的,SYN報(bào)文是用來同步的。但是關(guān)閉連接時(shí),當(dāng)服務(wù)端收到FIN報(bào)文時(shí),很可能并不會(huì)立即關(guān)閉SOCKET,所以只能先回復(fù)一個(gè)ACK報(bào)文,告訴客戶端,"你發(fā)的FIN報(bào)文我收到了"。只有等到我服務(wù)端所有的報(bào)文都發(fā)送完了,我才能發(fā)送FIN報(bào)文,因此不能一起發(fā)送。故需要四次揮手。
RST是什么,為什么會(huì)出現(xiàn)
RST 是一個(gè)特殊的標(biāo)記,用來表示當(dāng)前應(yīng)該立即終止連接。以下這些情況都會(huì)產(chǎn)生RST:
* 向一個(gè)未被監(jiān)聽的端口發(fā)送數(shù)據(jù)
* 對(duì)方已經(jīng)調(diào)用 close 關(guān)閉連接
* 存在一些數(shù)據(jù)未處理(接收緩沖區(qū)),請求關(guān)閉連接時(shí),會(huì)發(fā)送RST強(qiáng)制關(guān)閉
* 某些請求發(fā)生了超時(shí)
為什么服務(wù)器會(huì)有大量closewait
半關(guān)閉的狀態(tài)下的服務(wù)器連接會(huì)處于closewait狀態(tài),直到服務(wù)器發(fā)送了FIN。
那么在應(yīng)用層則是調(diào)用socket.close()會(huì)執(zhí)行FIN的發(fā)送,如果服務(wù)器出現(xiàn)大量CLOSE_WAIT狀態(tài)的連接,那么有可能的原因:
* 服務(wù)器壓力過大,根本來不及調(diào)用close
* 存在連接泄露問題(Bug),服務(wù)器未及時(shí)關(guān)閉連接
四次揮手釋放連接時(shí),等待2MSL的意義
為了保證客戶端發(fā)送的最后一個(gè)ACK報(bào)文段能夠到達(dá)服務(wù)器。因?yàn)檫@個(gè)ACK有可能丟失,從而導(dǎo)致處在LAST-ACK狀態(tài)的服務(wù)器收不到對(duì)FIN-ACK的確認(rèn)報(bào)文。服務(wù)器會(huì)超時(shí)重傳這個(gè)FIN-ACK,接著客戶端再重傳一次確認(rèn),重新啟動(dòng)時(shí)間等待計(jì)時(shí)器。最后客戶端和服務(wù)器都能正常的關(guān)閉。假設(shè)客戶端不等待2MSL,而是在發(fā)送完ACK之后直接釋放關(guān)閉,一但這個(gè)ACK丟失的話,服務(wù)器就無法正常的進(jìn)入關(guān)閉連接狀態(tài)。
MSL是Maximum Segment
Lifetime的英文縮寫,可譯為“最長報(bào)文段壽命”,它是任何報(bào)文在網(wǎng)絡(luò)上存在的最長時(shí)間,超過這個(gè)時(shí)間報(bào)文將被丟棄。我們都知道IP頭部中有個(gè)TTL字段,TTL是time
to
live的縮寫,可譯為“生存時(shí)間”,這個(gè)生存時(shí)間是由源主機(jī)設(shè)置初始值代表一個(gè)IP數(shù)據(jù)包可以經(jīng)過的最大路由數(shù),每經(jīng)過一個(gè)路由器,它的值就減1,當(dāng)此值為0則數(shù)據(jù)報(bào)被丟棄,同時(shí)發(fā)送ICMP報(bào)文通知源主機(jī)。RFC793中規(guī)定MSL為2分鐘,但這完全是從工程上來考慮,對(duì)于現(xiàn)在的網(wǎng)絡(luò),常用值30秒或1分鐘。因此TCP允許不同的實(shí)現(xiàn)可根據(jù)具體情況使用更小的MSL值。
最后,限于筆者經(jīng)驗(yàn)水平有限,歡迎讀者就文中的觀點(diǎn)提出寶貴的建議和意見。如果想獲得更多的學(xué)習(xí)資源或者想和更多的是技術(shù)愛好者一起交流,可以關(guān)注我的公眾號(hào)『全菜工程師小輝』后臺(tái)回復(fù)關(guān)鍵詞領(lǐng)取學(xué)習(xí)資料、進(jìn)入前后端技術(shù)交流群和程序員副業(yè)群。同時(shí)也可以加入程序員副業(yè)群Q群:735764906?一起交流。
熱門工具 換一換