三次握手和四次揮手以及面試題

2021-09-10 02:45:12 字數 4203 閱讀 5091

在正常情況下,tcp要經過三次握手建立連線,四次揮手斷開連線。

客戶端呼叫connect()傳送乙個帶syn標誌的tcp報文(syn=j)到伺服器。並進入syn_send狀態,阻塞等待伺服器應答。

伺服器收到syn包,必須確認客戶的syn(ack=j+1),同時自己也傳送乙個syn包(syn=k),即syn+ack包,表示同意建立連線,此時伺服器進入syn_recv狀態

客戶端收到伺服器的syn+ack包,從connect()返回,進入estabulished狀;向伺服器傳送確認包ack(ack=k+1),此包傳送完畢,伺服器進estabulished狀態,完成三次握手。

由於tcp連線是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的資料傳送任務後就能傳送乙個fin來終止這個方向的連線。收到乙個 fin只意味著這一方向上沒有資料流動,乙個tcp連線 在收到乙個fin後仍能傳送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。tcp連線的拆除需要傳送四個包,因此稱為四次揮手。客戶端或伺服器均可主動發起揮手動作,製造socket程式設計中,任何一方執行close()操作即可產生揮手操作。

tcp客戶端傳送乙個fin,用來關閉客戶到伺服器的資料傳送。

伺服器收到這個fin,它發回乙個ack,確認序號為收到的序號加1。和syn一 樣,乙個fin將占用乙個序號。

伺服器關閉客戶端的連線,傳送乙個fin給客戶端。

客戶段發回ack報文確認,並將確認序號設定為收到序號加1。

tcp協議的連線是全雙工連線,乙個tcp連線存在雙向的讀寫通道。 

簡單說來是 「先關讀,後關寫」,一共需要四個階段。以客戶端發起關閉連線為例:

第一階段客戶端傳送完資料之後,向伺服器傳送乙個fin資料段,序列號為i

1.伺服器收到fin(i)後,返回確認段ack,序列號為i+1關閉伺服器讀通道

2.客戶端收到ack(i+1)後,關閉客戶端寫信道

(此時,客戶端仍能通過讀通道讀取伺服器的資料,伺服器仍能通過寫信道寫資料)

第二階段伺服器傳送完資料之後,向客戶端傳送乙個fin資料段,序列號為j;

3.客戶端收到fin(j)後,返回確認段ack,序列號為j+1關閉客戶端讀通道

4.伺服器收到ack(j+1)後,關閉伺服器寫信道

主動斷開連線的一方會進入time_wait狀態。

兩次:假設第二個報文丟失,伺服器認為連線已經建立好了,但是客戶端認為沒有建立好連線,進行重傳。假設第二個報文總是丟失,伺服器會產生很多無效連線,占用資源。四次或五次就多餘了。

這是因為服務端的listen狀態下的socket當收到syn報文的建連請求後,它可以把ack和syn(ack起 應答作用,而syn起同步作用)放在乙個報文裡來傳送。但關閉連線時,當收到對方的fin報文通知時,它僅僅表示對方沒有資料傳送給你了;但未必你所有的資料都全部傳送給對方了,所以你可以未必會馬上會關閉socket,也即你可能還需要傳送一些資料給對方之後,再傳送fin報文給對方來表示你同意現在可以關閉連線了,所以它這裡的ack報文和fin報文多數情況下都是分開傳送的。

保證tcp協議的雙全工能夠可靠關閉。假設客戶端直接closed了,由於ip協議的不可靠性或者其它網路原因導致最後乙個ack丟失伺服器端就會在超時之後繼續傳送fin,此時由於客戶端已經closed了,就找不到與重發的fin對應的連線,最後伺服器就會收到rst而不是ack,伺服器就會以為是連線錯誤把問題報告給高層。這樣的情況雖然不會造成資料丟失,但是卻導致tcp協議不符合可靠連線的要求。所以,客戶端不是直接進入closed,而是要保持time_wait,此時客戶端程序已經不在了,但是tcp連線還在,仍然可以傳送報文。當再次收到fin的時候,能夠保證對方收到ack,最後正確的關閉連線

保證這次連線的重複資料段在網路中消失。如果客戶端直接closed,然後又再向server發起乙個新連線,我們不能保證這個新連線與剛關閉的連線的埠號是不同的。也就是說有可能新連線和老連線的埠號是相同的。一般來說不會發生什麼問題,但是還是有特殊情況出現:假設新連線和已經關閉的老連線埠號是一樣的,如果前一次連線的某些資料仍然滯留在網路中,這些延遲資料在建立新連線之後才到達伺服器,由於新連線和老連線的埠號是一樣的,又因為tcp協議判斷不同連線的依據是socket pair,於是,tcp協議就認為那個延遲的資料是屬於新連線的,這樣就和真正的新連線的資料報發生混淆了。所以tcp連線還要在time_wait狀態等待2倍msl,這樣可以保證本次連線的所有資料都從網路中消失。

msl是tcp報文的最大生存時間,一般msl是60s, cat /proc/sys/net/ipv4/tcp_fin_timeout 檢視msl的值。

主動斷開連線的一方要進入time_wait,伺服器主動斷開連線,進入time_wait期間不能繫結成功,解決方案:對指定的埠號進行埠復用。

int opt = 1;

setsockopt(listenfd, sol_socket, so_reuseaddr, &opt, sizeof(opt));

這些埠都是伺服器臨時分配,無法用so_reuseaddr選項解決這個問題。

net.ipv4.tcp_syncookies = 1 表示開啟syn cookies。當出現syn等待佇列溢位時,啟用cookies來處理,可防範少量syn攻擊,預設為0,表示關閉;

net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將time-wait sockets重新用於新的tcp連線,預設為0,表示關閉;

net.ipv4.tcp_tw_recycle = 1 表示開啟tcp連線中time-wait sockets的快速**,預設為0,表示關閉。

net.ipv4.tcp_fin_timeout = 30 修改系預設的timeout 時間

然後執行 /sbin/sysctl -p 讓引數生效。

/etc/sysctl.conf是乙個允許改變正在執行中的linux系統的介面,它包含一些tcp/ip堆疊和虛擬記憶體系統的高階選項,修改核心引數永久生效。
簡單來說,就是開啟系統的time_wait重用和快速**。

如果以上配置調優後效能還不理想,可繼續修改一下配置:

vi /etc/sysctl.conf

net.ipv4.tcp_keepalive_time = 1200 

#表示當keepalive起用的時候,tcp傳送keepalive訊息的頻度。預設是2小時,改為20分鐘。

net.ipv4.ip_local_port_range = 1024 65000 

#表示用於向外連線的埠範圍。預設情況下很小:32768到61000,改為1024到65000。

net.ipv4.tcp_max_syn_backlog = 8192 

#表示syn佇列的長度,預設為1024,加大佇列長度為8192,可以容納更多等待連線的網路連線數。

net.ipv4.tcp_max_tw_buckets = 5000 

#表示系統同時保持time_wait套接字的最大數量,如果超過這個數字,time_wait套接字將立刻被清除並列印警告資訊。

預設為180000,改為5000。對於apache、nginx等伺服器,上幾行的引數可以很好地減少time_wait套接字數量,但是對於 squid,效果卻不大。此項引數可以控制time_wait套接字的最大數量,避免squid伺服器被大量的time_wait套接字拖死。

三次握手四次揮手常見面試題

答 因為當server端收到client端的syn連線請求報文後,可以直接傳送syn ack報文。其中ack報文是用來應答的,syn報文是用來同步的。但是關閉連線時,當server端收到fin報文時,很可能並不會立即關閉socket,所以只能先回覆乙個ack報文,告訴client端,你發的fin報文...

三次握手和四次揮手

三次握手和四次揮手如圖所示 為什麼是三次握手而不是兩次 因為當客戶端第傳送syn到服務端的時候,如果有幾次請求是因為網路等原因延時等情況的時候,如果沒有第三次握手的確定。服務端就會認為客戶端重寫傳送請求了,就會去開啟連線相應。為什麼關閉連線的時候是四次握手而不是三次?當客戶端傳送請求關閉連線的時候,...

三次握手和四次揮手

tcp三次握手和四次揮手的全過程 tcp是主機對主機層的傳輸控制協議,提供可靠的連線服務,採用三次握手確認建立乙個連線 位碼即tcp標誌位,有6種表示 syn synchronous建立連線 ack acknowledgement 表示響應 確認 psh push表示有data資料傳輸 fin fi...