TCP协议通讯流程(三次握手及四次挥手)
TCP協議通訊流程(三次握手及四次揮手)
文章目錄
- TCP協議通訊流程(三次握手及四次揮手)
- 一、服務器端
- 二、客戶端
- 三、三次握手四次揮手
- 三、具體流程
- 四、相關注意事項
一、服務器端
二、客戶端
三、三次握手四次揮手
-
1 . 三次握手
-
在客戶端向服務器建立鏈接的過程中:客戶端首先創建自己的socket
-
調用connect發起鏈接服務器的請求
-
其中connect函數會發出SYN段并阻塞等待服務器的響應 (第一次)
-
服務器收到客戶端的鏈接請求SYN,會應答客戶端,向客戶端發送一個SYN-ACK,表示同意建立連接請求 (第二次)
-
客戶端收到服務器端的SYN-ACK后會從connect返回,同時向服務器端再應答一個ACK段; (第三次)
-
2.四次揮手
-
在數據傳輸的過程中:建立連接后,TCP協議提供全雙工的通信服務(全雙工:在同一條鏈接中,同一時刻通信雙方都可以寫數據)。
-
服務器在調用socket創建出socket文件描述符后,再調用bind綁定ip及端口號,服務器在調用accept獲取客戶端,調用完accept后立即調用recv函數(阻塞,跟read讀取管道一樣)
-
在這個時間客戶端調用send函數向服務器端發送請求(和write管道一樣),服務器收到從recv返回的請求,在對客戶端的請求進行處理,在這期間客戶端調用send函數阻塞等待
-
服務器端調再用send把響應結果發給客戶端,再次調用recv讀取客戶端請求
-
在斷開鏈接的過程中(一般都是客戶端主動斷開鏈接,服務器畢竟不是為一個客戶服務):如果客戶端不在請求了,就會調用close函數關閉鏈接,客戶端就會向服務器端發送一個FIN段,表示我要斷開鏈接了 (第一次)
-
此時服務器端在響應完客戶端的請求后,沒有在收到客戶端的請求,一直阻塞在recv處,此時收到客戶端發送的FIN后,會向客戶端回應一個ACK,同時recv會返回0 (第二次)
-
服務器端recv返回后,服務器端就直到客戶端要關閉鏈接了,也調用close函數關閉連接,再向客戶端發送一個FIN (第三次)
-
客戶端收到ACK和FIN后,再向服務器端發送一個ACK (第四次)
三、具體流程
- 服務端狀態轉化:
- [CLOSED -> LISTEN] 服務器端調用listen后進入LISTEN狀態, 等待客戶端連接;
- [LISTEN -> SYN_RCVD] 一旦監聽到連接請求(同步報文段), 就將該連接放入內核等待隊列中, 并向客戶端發送SYN確認報文.
- [SYN_RCVD -> ESTABLISHED] 服務端一旦收到客戶端的確認報文ACK, 就進入ESTABLISHED狀態, 可以進行讀寫數據了
- [ESTABLISHED -> CLOSE_WAIT] 當客戶端主動關閉連接(調用close), 服務器會收到結束報文段, 服務器返回確認報文段ACK并進入CLOSE_WAIT;
- [CLOSE_WAIT -> LAST_ACK] 進入CLOSE_WAIT后說明服務器準備關閉連接(需要處理完之前的數據); 當服務器真正調用close關閉連接時, 會向客戶端發送FIN, 此時服務器進入LAST_ACK狀態, 等待最后一個ACK到來(這個ACK是客戶端確認收到了FIN)
- [LAST_ACK -> CLOSED] 服務器收到了對FIN的ACK, 徹底關閉連接
- 客戶端狀態變化:
- [CLOSED -> SYN_SENT] 客戶端調用connect, 發送同步報文段;
- [SYN_SENT -> ESTABLISHED] connect調用成功, 則進入ESTABLISHED狀態冰箱服務器端發送一個ACK, 開始讀寫數據;
- [ESTABLISHED -> FIN_WAIT_1] 客戶端主動調用close時, 向服務器發送結束報文段FIN, 同時進入FIN_WAIT_1;
- [FIN_WAIT_1 -> FIN_WAIT_2] 客戶端收到服務器對結束報文段的確認, 則進入FIN_WAIT_2, 開始等待服務器的結束報文段;
- [FIN_WAIT_2 -> TIME_WAIT] 客戶端收到服務器發來的結束報文段, 進入TIME_WAIT, 并發出LAST_ACK;
- [TIME_WAIT -> CLOSED] 客戶端要等待一個2MSL(MaxSegment Life, 報文最大生存時間)的時間, 才會進入CLOSED狀態
四、相關注意事項
-
1 . 客戶端為什么不需要bind?
-
首先服務器端bind是因為如果客戶端要訪問服務器端,就必須要服務器端端“地址”,也就是ip+端口號,這樣客戶端才能找到服務器,進行通信
-
如果服務器端不進行bind操作,那么操作系統就會隨機分配端口號給服務器,那么客戶端就不能和服務器端進行通信。
-
而客戶端為什么不需要bind,是因為如果客戶端bind一個ip + 端口,那么如果一個pc上有多個用戶,那么bind同一個端口就會出錯(如果一臺pc上只有一個用戶也是可以bind)。
-
2 . 為什么要進行三次握手?
-
為了防止無效的連接請求報文到達服務器而引起錯誤。
-
TCP發起建立連接的一方不會一直等待對方的回復,如果超時,他再次發起這個請求,上一個作廢。
-
假設A給服務器發送了一個請求,但是由于網絡原因遲遲沒有到達B服務器。由于一直沒收到服務器端的回復確認,所以就進行超時重傳,上個就舍棄了。
-
然后新的請求很快的到達了B服務器,然后B服務器也很快的進行了響應,如果是兩次握手的話,這樣就建立了連接
-
但是上次因網絡問題遲遲未到的第一個請求這時到達了B服務器,服務器依然會當成新的連接請求進行響應,(服務器只要響應,第二次握手就完成了)這時又會建立連接,這就會出現建立了兩個連接的局面,
-
然后這就會出現很多問題,例如服務器端認為完成了握手,可以發送數據了,于是一直處于等待數據狀態,而發送端不理睬服務器端發來的請求(因為發送端的那個請求早就被清除了),不去發送數據,后果就是服務器一直等,這樣就會浪費很多服務器資源
-
如果是三次握手的話,就會避免這個問題,因為比如第二次的新請求到達時,發送端就會又給服務器端發送個確認請求,表示接收到了,這樣遲到的那個請求到達服務器端,然后返回到發送端時,發送端并不會響應。然后這個連接并不會建立,服務器也就不會白白等待。
-
3.為什么要進行四次揮手?
-
確保數據能夠完整傳輸。
-
當被動方收到主動方的FIN報文通知時,它僅僅表示主動方沒有數據再發送給被動方了。
-
但未必被動方所有的數據都完整的發送給了主動方,所以被動方不會馬上關閉SOCKET,它可能還需要發送一些數據給主動方后,(按照常理的話,第二次和第三次揮手應該一起回復FIN和ACK的,但是因為服務器端可能有數據沒發完,所以不能也立刻去主動申請關閉,所以要把ACK和FIN分開)再發送FIN報文給主動方,告訴主動方同意關閉連接,所以這里的ACK報文和FIN報文多數情況下都是分開發送的。
-
4.timewite的產生的原因及作用?
-
為實現TCP全雙工連接的可靠釋放
-
假設發起主動關閉的一方(client)最后發送的ACK在網絡中丟失,由于TCP協議的重傳機制,執行被動關閉的一方(server)將會重發其FIN
-
在該FIN到達client之前,client必須維護這條連接狀態,也就說這條TCP連接所對應的資源(client方的local_ip,local_port)不能被立即釋放或重新分配
-
直到另一方重發的FIN達到之后,client重發ACK后,經過2MSL時間周期沒有再收到另一方的FIN之后,該TCP連接才能恢復初始的CLOSED狀態。
-
如果主動關閉一方不維護這樣一個TIME_WAIT狀態,那么當被動關閉一方重發的FIN到達時,主動關閉一方的TCP傳輸層會用RST包響應對方,這會被對方認為是有錯誤發生,然而這事實上只是正常的關閉連接過程,并非異常
-
確保第四次握手時發送方發送的ACK可以到達接收方 如果2MSL時間內沒有收到,則接收方會進行重發
-
確保當前連接的所有報文都已經過期(每個具體TCP實現必須選擇一個報文段最大生存時間MSL。它是任何報文段被丟棄前在網絡內的最長時間,2MSL足夠使所有報文過期了)
-
5.理解close_wait狀態?
-
close_wait狀態介紹:
-
客戶端主動關閉連接,服務器接收到客戶端的FIN,但是還沒有發送自己的FIN,此時的狀態為close_wait狀態,大量的close_wait狀態拖累服務器性能
-
close_wait產生的原因:
-
某種情況下客戶端關閉了連接,但是我方忙于讀寫,沒有關閉連接
-
解決方法:
-
思想:檢查出客戶端已經關閉的連接,他之所以會出現這種問題,肯定是服務器端的連接釋放的代碼存在問題
總結
以上是生活随笔為你收集整理的TCP协议通讯流程(三次握手及四次挥手)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络编程套接字(四)
- 下一篇: 网络基础(二)及HTTP协议