三次握手 && 四次揮手

      網友投稿 782 2025-04-02

      愿打開這篇文章能幫到你。


      @[toc]

      TCP連接的建立與終止

      TCP是一個面向連接的協議。無論哪一方向另一方發送數據之前,都必須先在雙方之間建立一條連接。

      三次握手

      為了建立一條TCP連接:

      1) 請求端(通常稱為客戶)發送一個 SYN段指明客戶打算連接的服務器的端口,以及初始序號(ISN)。這個SYN段為報文段1。 2) 服務器發回包含服務器的初始序號的 SYN報文段(報文段2)作為應答。同時,將確認序號設置為客戶的ISN加1以對客戶的SYN報文段進行確認。一個SYN將占用一個序號。 3) 客戶必須將確認序號設置為服務器的ISN加1以對服務器的SYN報文段進行確認(報文段3)。

      這三個報文段完成連接的建立。這個過程也稱為三次握手( three-way handshake)

      1)序號(sequence number):seq序號,占32位,用來標識從TCP源端向目的端發送的字節流,發起方發送數據時對此進行標記。 2)確認號(acknowledgement number):ack序號,占32位,只有ACK標志位為1時,確認序號字段才有效,ack=seq+1。 3)標志位(Flags):共6個,即URG、ACK、PSH、RST、SYN、FIN等。具體含義如下: URG:緊急指針(urgent pointer)有效。 ACK:確認序號有效。(這個) PSH:接收方應該盡快將這個報文交給應用層。 RST:重置連接。 SYN:發起一個新連接。(這個) FIN:釋放一個連接。(這個)

      一臺PC它的ISN有自己的增長規律,如果它在ASA里面,有些攻擊者他會不斷的去連接PC,PC這時候就會不斷的回復SYN,ACK。攻擊者就能得到不同節點時間段的ISN,然后用這些不同時間段的ISN來計算出PC的ISN增長規律,通過判斷ISN增長規律,攻擊者就有可能判斷出你的操作系統。

      一臺PC和某個主機已經建立了TCP連接,攻擊者想做一個會話劫持,它需要偽裝PC的IP地址、端口號、協議號。這些偽裝了還是不行,還得知道你的序列號在什么范圍。所以攻擊者這時候也會通過多次探測來猜測ISN的增長規律,當得到ISN的增長規律會就會把PC干掉,攻擊者自己連接到相應的主機。

      所以ASA就要防止這些攻擊者通過多次試探來獲取PC的ISN增長規律,因為一旦PC的ISN增長規律被獲取后,攻擊者就可以對我的操作系統進行判斷,而且還有可能造成更嚴重的會話劫持。所以ASA會對初始化序列號進行擾亂。

      當PC在T1時刻發送SYN的時候,經過ASA,ASA會把T1時刻的ISN隨機加一個數發走,在T2時刻發送SYN的時候,經過ASA,ASA又會把T2時刻的ISN隨機加一個會減去一個數發走。由于ASA總是會在ISN的數上隨機加上一個或者減去一個數,這樣的話,攻擊者在看你的ISN的時候就會覺得沒有規律可尋。

      SYN攻擊是指發送方不斷發送連接請求(第一個TCP包,SYN),待服務端發送回應(第2個TCP包,SYN+ACK),發送方收到服務端的回應后,卻不再發送第3個TCP包。這樣會造成服務端存在大量的打開的TCP連接(處于open狀態,但并不是established狀態),這樣會消耗服務端大量的系統資源(Socket內核資源)。這就是SYN攻擊。

      服務端在收到客戶端發來的SYN報文段后,會回復SYN+ACK報文段,此時這條連接已處于半打開狀態,會將該半打開狀態的連接放入一個隊列(listen監聽隊列)。

      需要注意的是,該回復的報文段(SYN+ACK)同樣存在超時重傳,如果一定時間內未收到客戶端發來的ACK報文段,服務端則會重傳SYN+ACK報文段。達到最大重傳次數后,將該條半打開連接從隊列中移除。

      SYN攻擊就是利用這個特點,不斷發起SYN報文段,但卻不回復對服務端SYN+ACK報文段的確認。造成服務端維護較多的半打開連接,消耗系統資源。而正常的連接請求,卻因為資源不足而無法響應或響應緩慢。

      發送方的實現方式有兩種(使用WinPCap可實現):

      發送使用真實的IP地址發關TCP連接請求,但在收到服務端回復后,不再發送第3個TCP包。 發送方再發送給TCP服務端的連接請求中,使用的是虛假的IP地址,這樣服務端回復給了虛假的IP地址。

      這兩種方式,對服務端來說,TCP服務端在發送了第2個TCP包后,都會一直得不到應答,直到超時。服務端會維持大量的這種狀態的SOCKET。

      題外話啊扯一點。

      1、過濾網關防護

      2、加固TCP/IP協議棧進行防范

      最后一招,也是最重要的一招:請專業的人來,咱做開發的不能不了解這些,但是咱畢竟是開發,術業有專攻。

      四次揮手

      建立一個連接需要三次握手,而終止一個連接要經過 4次握手。這由TCP的半關閉(half-close)造成的。既然一個TCP連接是全雙工(即數據在兩個方向上能同時傳遞),因此每個方向必須單獨地進行關閉。

      這原則就是當一方完成它的數據發送任務后就能發送一個 FIN來終止這個方向連接。當一端收到一個FIN,它必須通知應用層另一端已經終止了那個方向的數據傳送。發送FIN通常是應用層進行關閉的結果。

      收到一個FIN只意味著在這一方向上沒有數據流動。一個 TCP連接在收到一個 FIN后仍能發送數據。而這對利用半關閉的應用來說是可能的,盡管在實際應用中只有很少的 TCP應用程序這樣做。

      TCP提供了連接的一端在結束它的發送后還能接收來自另一端數據的能力。這就是所謂的半關閉。

      為了使用這個特性,編程接口必須為應用程序提供一種方式來說明“我已經完成了數據傳送,因此發送一個文件結束( FIN)給另一端,但我還想接收另一端發來的數據,直到它給我發來文件結束(FIN)。

      如果應用程序不調用 close而調用shutdown,且第2個參數值為1,則插口的API支持半關閉。然而,大多數的應用程序通過調用close終止兩個方向的連接。

      圖顯示了一個半關閉的典型例子。

      普通問題解答

      TIME_WAIT狀態也稱為2MSL等待狀態。每個具體 TCP實現必須選擇一個報文段最大生存時間MSL(Maximum Segment Lifetime)。它是任何報文段被丟棄前在網絡內的最長時間。我們知道這個時間是有限的,因為 TCP報文段以IP數據報在網絡內傳輸,而IP數據報則有限制其生存時間的TTL字段。

      RFC 793 [Postel 1981c] 指出MSL為2分鐘。然而,實現中的常用值是30秒,1分鐘,或2分鐘。

      在實際應用中,對 IP數據報TTL的限制是基于跳數,而不是定時器。

      對一個具體實現所給定的 MSL值,處理的原則是:當 TCP執行一個主動關閉,并發回最后一個ACK,該連接必須在 TIME_WAIT狀態停留的時間為 2倍的MSL。這樣可讓TCP再次發送最后的ACK以防這個ACK丟失(另一端超時并重發最后的 FIN)。

      這種2MSL等待的另一個結果是這個 TCP連接在2MSL等待期間,定義這個連接的插口(客戶的IP地址和端口號,服務器的 IP地址和端口號)不能再被使用。這個連接只能在 2MSL結束后才能再被使用。

      遺憾的是,大多數 TCP實現(如伯克利版)強加了更為嚴格的限制。在 2MSL等待期間,插口中使用的本地端口在默認情況下不能再被使用。

      某些實現和API提供了一種避開這個限制的方法。使用插口API時,可說明其中的SO_REUSEADDR選項。它將讓調用者對處于2MSL等待的本地端口進行賦值,但我們將看到TCP原則上仍將避免使用仍處于2MSL連接中的端口。

      在連接處于2MSL等待時,任何遲到的報文段將被丟棄。因為處于 2MSL等待的、由該插口對(socket pair)定義的連接在這段時間內不能被再用,因此當要建立一個有效的連接時,來自該連接的一個較早替身( incarnation)的遲到報文段作為新連接的一部分不可能不被曲解(一個連接由一個插口對來定義。一個連接的新的實例( instance)稱為該連接的替身)。我們說圖18-13中客戶執行主動關閉并進入 TIME_WAIT是正常的。服務器通常執行被動關閉,不會進入TIME_WAIT狀態。這暗示如果我們終止一個客戶程序,并立即重新啟動這個客戶程序,則這個新客戶程序將不能重用相同的本地端口。這不會帶來什么問題,因為客戶使用本地端口,而并不關心這個端口號是什么。

      然而,對于服務器,情況就有所不同,因為服務器使用熟知端口。如果我們終止一個已經建立連接的服務器程序,并試圖立即重新啟動這個服務器程序,服務器程序將不能把它的這個熟知端口賦值給它的端點,因為那個端口是處于 2MSL連接的一部分。在重新啟動服務器程序前,它需要在1 ~ 4分鐘。

      這時會引發一個問題:

      1.如果發起斷開連接的這一方是客戶端,通常客戶端不需要指定本地端口號,在斷開連接后,重啟程序,會重新隨機選擇一個本地端口再去連接服務器。客戶端程序正常。

      三次握手 && 四次揮手

      2.如果發起斷開連接的這一方是服務端,通常服務端使用熟知的(固定的)監聽端口號,在斷開連接后,重啟程序,服務端監聽本地端口會失敗,會提示端口被使用。這是因為該端口在上次主動斷開連接后,還處理2MSL的time_wait狀態。解決方法是設置監聽端口的SO_REUSEADDR選項。注意:即使服務端設置了SO_REUSEADDR選項,使用服務端可以重用處理time-wait狀態的端口,但仍不允許存在相同的連接。什么意思呢?

      例如,服務器S 3.3.3.3 監聽 3000端口,客戶端 4.4.4.4,端口4000連接到S。這時,S主動斷開連接,然后,重啟了服務(服務端SOCKET設置了SO_REUSEADDR選項)。這時,如果客戶端仍使用4000去建立連接,仍會提示連接失敗

      像這種啊,你現在問我我肯定是不會背的,不過讓我抽出手來拿幾個項目練練,嘿嘿,就OK了。

      先來看下一臺生產環境中的各種tcp狀態的連接數:

      netstat -n| awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

      然后我們來分析下占比比較高的幾種狀態產生的原因和解決方法:

      CLOSE_WAIT

      咳咳,這就,很奇葩啊,是你的用戶量巨大嗎?不然就是服務器出問題了。如部分情況下不會執行socket的close方法,解決方法是查程序。

      TIME_WAIT

      time_wait是一個需要特別注意的狀態,他本身是一個正常的狀態,只在主動斷開那方出現,每次tcp主動斷開都會有這個狀態的,維持這個狀態的時間是2個msl周期(2分鐘),設計這個狀態的目的是為了防止我發了ack包對方沒有收到可以重發。那如何解決出現大量的time_wait連接呢?千萬不要把tcp_tw_recycle改成1,正確的姿勢應該是降低msl周期,也就是tcp_fin_timeout值,同時增加time_wait的隊列,防止滿了。

      為什么不能把tcp_tw_recycle改成1?

      改成1的后果是會導致一個路由器后面用戶有人能連你服務器有人telnet不通。

      原因是tcp_tw_recycle改成1后會啟用tcp的tcp_timestamps功能,這個功能簡單說就是所有的通信包是時間戳遞增的,如果收到了同一個IP下時間戳小的包那就說明是個老數據包,就會丟棄這個包。

      而一個路由器下每臺電腦的時間戳不是完全一致的,有的電腦的時間戳會小,導致這些電腦發出的通信包被直接丟棄了。

      (回頭做畢設的時候試一下)

      修改/etc/sysctl.conf 文件,內容如下:

      net.nf_conntrack_max = 1000000 #發送keepalive的心跳 net.ipv4.tcp_keepalive_time = 1200 net.ipv4.tcp_tw_reuse = 0 #不能改成1 否則NAT后面的客戶端可能連接不上 net.ipv4.tcp_tw_recycle = 0 net.ipv4.tcp_fin_timeout = 30 #timewait隊列最大數量 net.ipv4.tcp_max_tw_buckets = 262144 #建立連接握手過程的ack重發次數從5到3 net.ipv4.tcp_synack_retries = 3 #緩存syn請求數量 解決messsage日志中syn溢出日志 net.ipv4.tcp_max_syn_backlog = 8192 net.ipv4.tcp_syncookies = 1 #linux收包緩存 net.core.rmem_default=262144 net.core.wmem_default=262144 net.core.rmem_max=4194304 net.core.wmem_max=4194304 net.core.somaxconn=1024 vm.overcommit_memory = 1 vm.max_map_count=262144

      TCP釋放連接時之所以需要“四次揮手”,是因為FIN釋放連接報文與ACK確認接收報文是分別由第二次和第三次"握手"傳輸的。

      建立連接時,被動方服務器端結束CLOSED階段進入“握手”階段并不需要任何準備,可以直接返回SYN和ACK報文,開始建立連接。釋放連接時,被動方服務器,突然收到主動方客戶端釋放連接的請求時并不能立即釋放連接,因為還有必要的數據需要處理,所以服務器先返回ACK確認收到報文,經過CLOSE-WAIT階段準備好釋放連接之后,才能返回FIN釋放連接報文。

      在TCP里可以讓數個Application共享一個Port么?

      專治難題

      以下建立在==非惡意攻擊的前提下==

      第一次握手失敗

      出師未捷身先死哈。。。

      當客戶端想和服務端建立 TCP 連接的時候,首先第一個發的就是 SYN 報文,然后進入到 SYN_SENT 狀態。

      在這之后,如果客戶端遲遲收不到服務端的 SYN-ACK 報文(第二次握手),就會觸發超時重傳機制。

      不同版本的操作系統可能超時時間不同,有的 1 秒的,也有 3 秒的,這個超時時間是寫死在內核里的,如果想要更改則需要重新編譯內核,比較麻煩。

      而且==其重傳間隔2倍方遞增==。

      當客戶端在 1 秒后沒收到服務端的 SYN-ACK 報文后,客戶端就會重發 SYN 報文,那到底重發幾次呢?

      在 Linux 里,客戶端的 SYN 報文最大重傳次數由 tcp_syn_retries內核參數控制,這個參數是可以自定義的,默認值一般是 5。

      通常,第一次超時重傳是在 1 秒后,第二次超時重傳是在 2 秒,第三次超時重傳是在 4 秒后,第四次超時重傳是在 8 秒后,第五次是在超時重傳 16 秒后。沒錯,每次超時的時間是上一次的 2 倍。

      當第五次超時重傳后,會繼續等待 32 秒,如果服務端仍然沒有回應 ACK,客戶端就不再發送 SYN 包,然后斷開 TCP 連接。

      所以,總耗時是 1+2+4+8+16+32=63 秒,大約 1 分鐘左右。

      第二次握手失敗

      注意:對于報文段2(服務端的SYN+ACK),同樣會存在超時重傳。

      如果第二次握手丟了,那就好玩了。

      因為第二次握手報文里是包含對客戶端的第一次握手的 ACK 確認報文,所以,如果客戶端遲遲沒有收到第二次握手,那么客戶端就覺得可能自己的 SYN 報文(第一次握手)丟失了,于是客戶端就會觸發超時重傳機制,重傳 SYN 報文。

      如果第二次握手丟失了,服務端就收不到第三次握手,于是服務端這邊會觸發超時重傳機制,重傳 SYN-ACK 報文。

      在 Linux 下,SYN-ACK 報文的最大重傳次數由 tcp_synack_retries內核參數決定,默認值是 5。

      因此,當第二次握手丟失了,客戶端和服務端都會重傳。

      (預知后事如何,了解一下TCP報文丟棄機制)

      第三次握手失敗

      此時客戶端狀態進入到 ESTABLISH 狀態。

      因為這個第三次握手的 ACK 是對第二次握手的 SYN 的確認報文,所以當第三次握手丟失了,如果服務端那一方遲遲收不到這個確認報文,就會觸發超時重傳機制,重傳 SYN-ACK 報文,直到收到第三次握手,或者達到最大重傳次數。

      注意,ACK 報文是不會有重傳的,當 ACK 丟失了,就由對方重傳對應的報文。

      第一次揮手失敗

      如果第一次揮手丟失了,那么客戶端遲遲收不到被動方的 ACK 的話,也就會觸發超時重傳機制,重傳 FIN 報文,重發次數由 tcp_orphan_retries 參數控制。

      當客戶端重傳 FIN 報文的次數超過 tcp_orphan_retries 后,就不再發送 FIN 報文,直接進入到 close 狀態。

      第二次揮手失敗

      如果服務端的第二次揮手丟失了,客戶端就會觸發超時重傳機制,重傳 FIN 報文,直到收到服務端的第二次揮手,或者達到最大的重傳次數。

      這里提一下,當客戶端收到第二次揮手,也就是收到服務端發送的 ACK 報文后,客戶端就會處于 FIN_WAIT2 狀態,在這個狀態需要等服務端發送第三次揮手,也就是服務端的 FIN 報文。

      對于 close 函數關閉的連接,由于無法再發送和接收數據,所以FIN_WAIT2 狀態不可以持續太久,而 tcp_fin_timeout 控制了這個狀態下連接的持續時長,默認值是 60 秒。

      這意味著對于調用 close 關閉的連接,如果在 60 秒后還沒有收到 FIN 報文,客戶端(主動關閉方)的連接就會直接關閉。

      第三次揮手失敗

      內核是沒有權利替代進程關閉連接,必須由進程主動調用 close 函數來觸發服務端發送 FIN 報文。

      服務端處于 CLOSE_WAIT 狀態時,調用了 close 函數,內核就會發出 FIN 報文,同時連接進入 LAST_ACK 狀態,等待客戶端返回 ACK 來確認連接關閉。

      如果遲遲收不到這個 ACK,服務端就會重發 FIN 報文,重發次數仍然由 tcp_orphan_retries 參數控制,這與客戶端重發 FIN 報文的重傳次數控制方式是一樣的。

      第四次揮手失敗

      在 Linux 系統,TIME_WAIT 狀態會持續 60 秒后才會進入關閉狀態。

      然后,服務端(被動關閉方)沒有收到 ACK 報文前,還是處于 LAST_ACK 狀態。

      如果第四次揮手的 ACK 報文沒有到達服務端,服務端就會重發 FIN 報文,重發次數仍然由前面介紹過的 tcp_orphan_retries 參數控制。

      這個悲傷逆流成河啊。三次握手,四次揮手,哈哈。。。

      還記得那天晚上,我們躺在草坪上看星星,你問我的那個問題嗎?我給你的答復,很快我就要達成了。你的答復是啥來著?我忘了,忘咯。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:如何隱藏wps表格中的狀態欄(wps表格上面的菜單欄怎么隱藏了)
      下一篇:Excel工作表中快速插入空白單元格的方法
      相關文章
      亚洲色偷偷色噜噜狠狠99| 亚洲国产精品VA在线看黑人| 亚洲一区二区成人| 亚洲视频在线一区二区| 成人婷婷网色偷偷亚洲男人的天堂| ASS亚洲熟妇毛茸茸PICS| 亚洲黄色网址在线观看| 亚洲性天天干天天摸| 91大神亚洲影视在线| 久久亚洲AV成人无码国产| 亚洲va在线va天堂va888www| 亚洲AV无码成人精品区在线观看 | 亚洲一区二区三区AV无码| 亚洲黄片手机免费观看| 亚洲日韩涩涩成人午夜私人影院| 国产在亚洲线视频观看| 偷自拍亚洲视频在线观看99| 日韩精品成人亚洲专区| 亚洲国产电影av在线网址| 亚洲精品无码99在线观看| 国产成人亚洲综合| 亚洲精品无码MV在线观看| 久久精品国产69国产精品亚洲| 亚洲午夜福利在线观看| 亚洲成A人片在线观看WWW| 亚洲国产一区国产亚洲| 亚洲黄色免费网址| 亚洲AV无码乱码在线观看代蜜桃 | 亚洲国产精品免费观看| 亚洲人成人无码.www石榴| 久久水蜜桃亚洲AV无码精品| 国产亚洲精品美女久久久久久下载| 亚洲AV无码乱码在线观看| 国产午夜亚洲精品国产成人小说| 亚洲精品国产字幕久久不卡| 亚洲日韩图片专区第1页| 亚洲人成电影在线观看网| 最新亚洲精品国偷自产在线| 亚洲变态另类一区二区三区| 亚洲福利精品一区二区三区| 亚洲熟女一区二区三区|