http://blog.csdn.net/chenhanzhun/article/details/41622555
2014
注:TCP 連接的建立和釋放在網(wǎng)絡(luò)協(xié)議中是比較重要的,由于本人理解也不是很透徹,歡迎各位批評指正。
前言
TCP 是面向連接的、可靠的字節(jié)流協(xié)議。因此,在傳輸數(shù)據(jù)之前通信雙方必須建立一個(gè) TCP 連接,建立 TCP 連接需要在服務(wù)器和客戶端之間進(jìn)行三次握手。通信雙方數(shù)據(jù)傳輸完畢之后進(jìn)行連接釋放,釋放連接需要在通信雙方之間進(jìn)行四次揮手。
TCP 狀態(tài)機(jī)
TCP 所謂的“連接”,只是通信雙方維護(hù)一個(gè)“連接狀態(tài)”,讓它看上去好像有連接一樣,其實(shí) TCP 連接是虛擬的連接,不是電路連接。首先看下 TCP 的狀態(tài)機(jī),狀態(tài)機(jī)是 TCP 連接與釋放的全過程。如下圖所示:
下面針對 TCP 狀態(tài)機(jī)所出現(xiàn)的各個(gè)狀態(tài)進(jìn)行簡要的分析:
- CLOSED:表示初始狀態(tài)。對服務(wù)端和客戶端雙方都一樣。
- LISTEN:表示監(jiān)聽狀態(tài)。服務(wù)端調(diào)用了 listen 函數(shù)使其處于監(jiān)聽狀態(tài),此時(shí)可以開始 accept (接收)客戶端的連接。
- SYN_SENT:表示客戶端已經(jīng)發(fā)送了 SYN 報(bào)文段,則會處于該狀態(tài)。當(dāng)客戶端調(diào)用 connect 函數(shù)發(fā)起連接請求時(shí),首先發(fā) SYN 給服務(wù)端,然后自己進(jìn)入 SYN_SENT 狀態(tài),并等待服務(wù)端發(fā)送 ACK+SYN 作為請求應(yīng)答。
- SYN_RCVD:表示服務(wù)端收到客戶端發(fā)送 SYN 報(bào)文段。服務(wù)端收到這個(gè)報(bào)文段后,進(jìn)入 SYN_RCVD 狀態(tài),然后發(fā)送 ACK+SYN 給客戶端。
- ESTABLISHED:表示 TCP 連接已經(jīng)成功建立,通信雙方可以開始傳輸數(shù)據(jù)。服務(wù)端發(fā)送完 ACK+SYN 并收到來自客戶端的 ACK 后進(jìn)入該狀態(tài),客戶端收到來自服務(wù)器的 SYN+ACK 并發(fā)送 ACK 后也進(jìn)入該狀態(tài)。
- FIN_WAIT_1:表示主動關(guān)閉連接。無論哪方調(diào)用 close 函數(shù)發(fā)送 FIN 報(bào)文都會進(jìn)入這個(gè)這個(gè)狀態(tài)。
- FIN_WAIT_2:表示被動關(guān)閉方同意關(guān)閉連接。主動關(guān)閉連接方收到被動關(guān)閉方返回的 ACK 后,會進(jìn)入該狀態(tài)。
- TIME_WAIT:表示收到對方的 FIN 報(bào)文并發(fā)送了 ACK 報(bào)文,就等 2MSL 后即可回到 CLOSED 狀態(tài)了。如果 FIN_WAIT_1 狀態(tài)下,收到對方同時(shí)帶 FIN 標(biāo)志和 ACK 標(biāo)志的報(bào)文時(shí),可以直接進(jìn)入 TIME_WAIT 狀態(tài),而無須經(jīng)過 FIN_WAIT_2 狀態(tài)。
- CLOSING:表示雙方同時(shí)關(guān)閉連接。如果雙方幾乎同時(shí)調(diào)用 close 函數(shù),那么會出現(xiàn)雙方同時(shí)發(fā)送 FIN 報(bào)文的情況,就會出現(xiàn) CLOSING 狀態(tài),表示雙方都在關(guān)閉連接。
- CLOSE_WAIT:表示被動關(guān)閉方等待關(guān)閉。當(dāng)收到對方調(diào)用 close 函數(shù)發(fā)送的 FIN 報(bào)文時(shí),回應(yīng)對方 ACK 報(bào)文,此時(shí)進(jìn)入 CLOSE_WAIT 狀態(tài)。
- LAST_ACK:表示被動關(guān)閉方發(fā)送 FIN 報(bào)文后,等待對方的 ACK 報(bào)文狀態(tài),當(dāng)收到 ACK 后進(jìn)入CLOSED狀態(tài)。
TCP 連接的建立
TCP 連接的正常建立過程通信雙方需要三次握手,其過程如下圖所示:
TCP 協(xié)議提供可靠的連接服務(wù),采用有保障的三次握手方式來創(chuàng)建一個(gè) TCP 連接。三次握手的具體過程如下:
- 客戶端進(jìn)程向服務(wù)端發(fā)出連接請求,請求報(bào)文的報(bào)文段首部中的控制位標(biāo)志 SYN=1(有關(guān) TCP 控制位信息參考《TCP 協(xié)議》),由于是首次請求建立連接,因此,控制位標(biāo)志 ACK=0,該報(bào)文段包含計(jì)算機(jī)隨機(jī)生成的初始序號 seq=x。發(fā)送請求連接的 TCP 報(bào)文段,此時(shí)客戶端進(jìn)程進(jìn)入 SYN_SENT 狀態(tài),這是 TCP 連接的第一次握手。
- 服務(wù)端收到客戶端發(fā)來的請求報(bào)文后,若同意建立連接,則向客戶端發(fā)送確認(rèn)。確認(rèn)報(bào)文中的控制位 SYN=1,ACK=1,確認(rèn)應(yīng)答號 ack=x+1(即在接收到序列號值基礎(chǔ)上加 1 ),并且發(fā)送自己的一個(gè)初始序列號 seq=y(即請求與客戶端連接)。此時(shí),服務(wù)端進(jìn)入SYN_RCVD狀態(tài),這是TCP連接的第二次握手。
- 客戶端進(jìn)程收到服務(wù)端進(jìn)程的確認(rèn)報(bào)文后,還要向服務(wù)端發(fā)出確認(rèn)信息。確認(rèn)報(bào)文段的控制位 ACK=1,確認(rèn)應(yīng)答號 ack=y+1(即在接收到序列號值基礎(chǔ)上加 1 ),此時(shí),客戶端進(jìn)入 ESTABLISHED 狀態(tài)。服務(wù)器收到來自客戶端的確認(rèn)應(yīng)答信息也進(jìn)入 ESTABLISHED 狀態(tài)。這是TCP連接的第三次握手。此時(shí),TCP 連接成功建立。
同時(shí)打開連接請求
正常情況下,通信一方請求建立連接,另一方響應(yīng)該請求,但是如果出現(xiàn),通信雙方同時(shí)請求建立連接時(shí),則連接建立過程并不是三次握手過程,而且這種情況的連接也只有一條,并不會建立兩條連接。同時(shí)打開連接時(shí),兩邊幾乎同時(shí)發(fā)送 SYN,并進(jìn)入 SYN_SENT 狀態(tài),當(dāng)每一端收到 SYN 時(shí),狀態(tài)變?yōu)?SYN_RCVD,同時(shí)雙方都再發(fā) SYN 和 ACK 作為對收到的 SYN 進(jìn)行確認(rèn)應(yīng)答。當(dāng)雙方都收到 SYN 及相應(yīng)的 ACK 時(shí),狀態(tài)變?yōu)?ESTABLISHED。其過程入下:
TCP 連接釋放
由于 TCP 連接是全雙工的,因此每個(gè)方向都必須單獨(dú)進(jìn)行關(guān)閉。原則是主動關(guān)閉的一方發(fā)送一個(gè) FIN 報(bào)文來表示終止這個(gè)方向的連接,收到一個(gè) FIN 意味著這個(gè)方向不再有數(shù)據(jù)流動,但另一個(gè)方向仍能繼續(xù)發(fā)送數(shù)據(jù),直到另一個(gè)方向也發(fā)送 FIN 報(bào)文。TCP 連接釋放的過程如下圖所示:
以下是釋放連接的四次揮手過程:
- 客戶端進(jìn)程主動向服務(wù)端發(fā)出連接釋放請求報(bào)文段,并停止發(fā)送數(shù)據(jù),主動關(guān)閉 TCP 連接。釋放連接報(bào)文段中控制位 FIN=1,序列號為 seq=i,發(fā)送該報(bào)文段之后客戶端進(jìn)入FIN_WAIT_1(終止等待1)狀態(tài),等待服務(wù)器的確認(rèn)。這是 TCP 連接釋放的第一次揮手。
- 服務(wù)器收到連接釋放請求報(bào)文段后即發(fā)出確認(rèn)釋放連接的報(bào)文段,該報(bào)文段中控制位 ACK=1,確認(rèn)應(yīng)答號為 ack=i+1,然后服務(wù)器進(jìn)入CLOSE_WAIT(關(guān)閉等待)狀態(tài)。此時(shí) TCP 處于半關(guān)閉狀態(tài),即客戶端已經(jīng)不向服務(wù)器發(fā)送數(shù)據(jù),但服務(wù)器仍可向客戶端發(fā)送數(shù)據(jù)。這是TCP連接釋放的第二次揮手。
- 客戶端收到服務(wù)器的確認(rèn)信息后,就進(jìn)入了FIN_WAIT_2(終止等待2)狀態(tài),等待服務(wù)器發(fā)出連接釋放請求報(bào)文段,若沒有數(shù)據(jù)需要傳輸,服務(wù)器被動向客戶端發(fā)出鏈接釋放請求報(bào)文段中,報(bào)文段中控制位 FIN=1,序列號 seq=j,此時(shí)服務(wù)器進(jìn)入LAST_ACK(最后確認(rèn))狀態(tài),等待客戶端的確認(rèn)應(yīng)答。這是 TCP 連接釋放的第三次揮手。
- 客戶端收到服務(wù)器的連接釋放請求后,必須對此發(fā)出確認(rèn)。確認(rèn)報(bào)文段中控制位 ACK=1,確認(rèn)應(yīng)答號 ack=j+1,客戶端發(fā)出確認(rèn)應(yīng)答信息之后后進(jìn)入TIME_WAIT(時(shí)間等待)狀態(tài)。在這段時(shí)間內(nèi) TCP連接并沒有釋放,必須等待 2MSL 時(shí)間后,客戶端才進(jìn)入 CLOSED 狀態(tài)。服務(wù)器收到了客戶端的確認(rèn)應(yīng)答后,就進(jìn)入了 CLOSED 狀態(tài)。直到客戶端和服務(wù)器都進(jìn)入 CLOSED 狀態(tài)后,連接就完全釋放了,這是TCP連接釋放的第四次揮手。
同時(shí)關(guān)閉連接
正常情況下,通信一方請求連接關(guān)閉,另一方響應(yīng)連接關(guān)閉請求,并且被動關(guān)閉連接。但是若出現(xiàn)同時(shí)關(guān)閉連接請求時(shí),通信雙方均從 ESTABLISHED 狀態(tài)轉(zhuǎn)換為 FIN_WAIT_1 狀態(tài)。任意一方收到對方發(fā)來的 FIN 報(bào)文段后,其狀態(tài)均由 FIN_WAIT_1轉(zhuǎn)變到 CLOSING 狀態(tài),并發(fā)送最后的 ACK 數(shù)據(jù)段。當(dāng)收到最后的 ACK 數(shù)據(jù)段后,狀態(tài)轉(zhuǎn)變化 TIME_WAIT,在等待 2MSL 時(shí)間后進(jìn)入到 CLOSED 狀態(tài),最終釋放整個(gè) TCP 傳輸連接。其過程入下:
TCP 相關(guān)疑問
為什么在 TCP 協(xié)議里,建立連接是三次握手,而關(guān)閉連接卻是四次握手? 因?yàn)楫?dāng)處于 LISTEN 狀態(tài)的服務(wù)器端收到來自客戶端的 SYN 報(bào)文(客戶端希望新建一個(gè)TCP連接)時(shí),它可以把 ACK (確認(rèn)應(yīng)答)和 SYN (同步序號)放在同一個(gè)報(bào)文里來發(fā)送給客戶端。但在關(guān)閉 TCP 連接時(shí),當(dāng)收到對方的 FIN 報(bào)文時(shí),對方僅僅表示對方已經(jīng)沒有數(shù)據(jù)發(fā)送給你了,但是你自己可能還有數(shù)據(jù)需要發(fā)送給對方,則等你發(fā)送完剩余的數(shù)據(jù)給對方之后,再發(fā)送 FIN 報(bào)文給對方來表示你數(shù)據(jù)已經(jīng)發(fā)送完畢,并請求關(guān)閉連接,所以通常情況下,這里的 ACK 報(bào)文和 FIN 報(bào)文都是分開發(fā)送的。
為什么一定要進(jìn)行三次握手?
當(dāng)客戶端向服務(wù)器端發(fā)送一個(gè)連接請求時(shí),由于某種原因長時(shí)間駐留在網(wǎng)絡(luò)節(jié)點(diǎn)中,無法達(dá)到服務(wù)器端,由于 TCP 的超時(shí)重傳機(jī)制,當(dāng)客戶端在特定的時(shí)間內(nèi)沒有收到服務(wù)器端的確認(rèn)應(yīng)答信息,則會重新向服務(wù)器端發(fā)送連接請求,且該鏈接請求得到服務(wù)器端的響應(yīng)并正常建立連接,進(jìn)而傳輸數(shù)據(jù),當(dāng)數(shù)據(jù)傳輸完畢,并釋放了此次 TCP 連接。若此時(shí)第一次發(fā)送的連接請求報(bào)文段延遲了一段時(shí)間后,到達(dá)了服務(wù)器端,本來這是一個(gè)早已失效的報(bào)文段,但是服務(wù)器端收到該鏈接請求后誤以為客戶端又發(fā)出了一次新的連接請求,于是服務(wù)器端向客戶端發(fā)出確認(rèn)應(yīng)答報(bào)文段,并同意建立連接。如果沒有采用三次握手建立連接,由于服務(wù)器端發(fā)送了確認(rèn)應(yīng)答信息,則表示新的連接已成功建立,但是客戶端此時(shí)并沒有向服務(wù)器端發(fā)出任何連接請求,因此客戶端忽略服務(wù)器端的確認(rèn)應(yīng)答報(bào)文,更不會向服務(wù)器端傳輸數(shù)據(jù)。而服務(wù)器端卻認(rèn)為新的連接已經(jīng)建立了,并在一直等待客戶端發(fā)送數(shù)據(jù),這樣服務(wù)器端一直處于等待接收數(shù)據(jù),直到超出計(jì)數(shù)器的設(shè)定值,則認(rèn)為客戶端出現(xiàn)異常,并且關(guān)閉這個(gè)連接。在這個(gè)等待的過程中,浪費(fèi)服務(wù)器的資源。如果采用三次握手,客戶端就不會向服務(wù)端發(fā)出確認(rèn)應(yīng)答信息,服務(wù)器端由于沒有收到客戶端的確認(rèn)應(yīng)答信息,從而判定客戶端并沒有請求建立連接,從而不建立該連接。
為什么需要在 TIME_WAIT 狀態(tài)必須等待 2MSL 時(shí)間,而不直接給進(jìn)入 CLOSED 狀態(tài)?
主要有兩個(gè)原因:
- TIME_WAIT 確保有足夠的時(shí)間讓對端收到了ACK,如果被動關(guān)閉的那方?jīng)]有收到 ACK,就會觸發(fā)被動端重發(fā) FIN。因?yàn)樽詈笠淮未_認(rèn)應(yīng)答 ACK 報(bào)文段很有可能丟失,因而使被動關(guān)閉方處于在LAST_ACK 狀態(tài)的,此時(shí)被動關(guān)閉方會重發(fā)這個(gè) FIN+ACK 報(bào)文段,在這等待的 2MSL 時(shí)間內(nèi)主動關(guān)閉方重新收到這個(gè)被動關(guān)閉方重發(fā)的 FIN+ACK 報(bào)文段,因此,主動關(guān)閉方會重新發(fā)送確認(rèn)應(yīng)答信息,從而重新啟動 2MSL 計(jì)時(shí)器,直到通信雙方都進(jìn)入 CLOSED 狀態(tài)。如果主動關(guān)閉方在 TIME_WAIT 狀態(tài)不等待一段時(shí)間就直接釋放連接并進(jìn)入 CLOSED 狀態(tài),那么主動關(guān)閉方無法收到來自被動關(guān)閉方重發(fā)的 FIN+ACK 報(bào)文段,也就不會再發(fā)送一次確認(rèn) ACK 報(bào)文段,因此被動關(guān)閉方就無法正常進(jìn)入CLOSED 狀態(tài)。
- 有足夠的時(shí)間讓這個(gè)連接不會跟后面的連接混在一起。防止已失效的請求連接出現(xiàn)在本連接中。在連接處于 2MSL 等待時(shí),任何遲到的報(bào)文段將被丟棄,因?yàn)樘幱?2MSL等待的、由該插口(插口是IP和端口對的意思,socket)定義的連接在這段時(shí)間內(nèi)將不能被再用,這樣就可以使下一個(gè)新的連接中不會出現(xiàn)這種舊的連接之前延遲的報(bào)文段。
參考資料:
《TCP/IP 詳解》
《TCP連接的建立和釋放》
《TCP/IP狀態(tài)變遷圖和TCP三次握手與四次揮手》
《TCP 的那些事兒》
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點(diǎn)擊舉報(bào)。