三次握手與四次揮手

三次握手

三次握手(Three-way Handshake)其實就是指建立一個TCP連接時递宅,需要客戶端和服務器總共發(fā)送3個包。進行三次握手的主要作用就是為了確認雙方的接收能力和發(fā)送能力是否正常萝勤、指定自己的初始化序列號為后面的可靠性傳送做準備。實質上其實就是連接服務器指定端口呐伞,建立TCP連接敌卓,并同步連接雙方的序列號和確認號,交換TCP窗口大小信息伶氢。

剛開始客戶端處于 Closed 的狀態(tài)趟径,服務端處于 Listen 狀態(tài)。 進行三次握手:

  • 第一次握手:客戶端給服務端發(fā)一個 SYN 報文癣防,并指明客戶端的初始化序列號 ISN(c)蜗巧。此時客戶端處于 SYN_SEND 狀態(tài)。

首部的同步位SYN=1蕾盯,初始序號seq=x幕屹,SYN=1的報文段不能攜帶數(shù)據(jù),但要消耗掉一個序號级遭。

  • 第二次握手:服務器收到客戶端的 SYN 報文之后望拖,會以自己的 SYN 報文作為應答,并且也是指定了自己的初始化序列號 ISN(s)挫鸽。同時會把客戶端的 ISN + 1 作為ACK 的值说敏,表示自己已經(jīng)收到了客戶端的 SYN,此時服務器處于 SYN_REVD 的狀態(tài)掠兄。

在確認報文段中SYN=1像云,ACK=1锌雀,確認號ack=x+1蚂夕,初始序號seq=y迅诬。

  • 第三次握手:客戶端收到 SYN 報文之后,會發(fā)送一個 ACK 報文婿牍,當然侈贷,也是一樣把服務器的 ISN + 1 作為 ACK 的值,表示已經(jīng)收到了服務端的 SYN 報文等脂,此時客戶端處于 ESTABLISHED 狀態(tài)俏蛮。服務器收到 ACK 報文之后,也處于 ESTABLISHED 狀態(tài)上遥,此時搏屑,雙方已建立起了連接。

確認報文段ACK=1粉楚,確認號ack=y+1辣恋,序號seq=x+1(初始為seq=x,第二個報文段所以要+1)模软,ACK報文段可以攜帶數(shù)據(jù)伟骨,不攜帶數(shù)據(jù)則不消耗序號。

發(fā)送第一個SYN的一端將執(zhí)行主動打開(active open)燃异,接收這個SYN并發(fā)回下一個SYN的另一端執(zhí)行被動打開(passive open)携狭。

在socket編程中,客戶端執(zhí)行connect()時回俐,將觸發(fā)三次握手逛腿。

為什么需要三次握手,兩次不行嗎仅颇?

  • 需要三次握手才能確認雙方的接收與發(fā)送能力是否正常鳄逾。
  • 某些網(wǎng)絡結點長時間滯留了,延誤到連接釋放以后的某個時間才到達服務端
  • 通信雙方確定序列號

什么是半連接隊列灵莲?

服務器第一次收到客戶端的 SYN 之后雕凹,就會處于 SYN_RCVD 狀態(tài),此時雙方還沒有完全建立其連接政冻,服務器會把此種狀態(tài)下請求連接放在一個隊列里枚抵,我們把這種隊列稱之為半連接隊列。

當然還有一個全連接隊列明场,就是已經(jīng)完成三次握手汽摹,建立起連接的就會放在全連接隊列中。如果隊列滿了就有可能會出現(xiàn)丟包現(xiàn)象苦锨。

這里在補充一點關于SYN-ACK 重傳次數(shù)的問題: 服務器發(fā)送完SYN-ACK包逼泣,如果未收到客戶確認包趴泌,服務器進行首次重傳,等待一段時間仍未收到客戶確認包拉庶,進行第二次重傳嗜憔。如果重傳次數(shù)超過系統(tǒng)規(guī)定的最大重傳次數(shù),系統(tǒng)將該連接信息從半連接隊列中刪除氏仗。 注意吉捶,每次重傳等待的時間不一定相同,一般會是指數(shù)增長皆尔,例如間隔時間為 1s呐舔,2s,4s慷蠕,8s......

ISN(Initial Sequence Number)是固定的嗎珊拼?

當一端為建立連接而發(fā)送它的SYN時,它為連接選擇一個初始序號流炕。ISN隨時間而變化澎现,因此每個連接都將具有不同的ISN。ISN可以看作是一個32比特的計數(shù)器浪感,每4ms加1 昔头。這樣選擇序號的目的在于防止在網(wǎng)絡中被延遲的分組在以后又被傳送,而導致某個連接的一方對它做錯誤的解釋影兽。

三次握手的其中一個重要功能是客戶端和服務端交換 ISN(Initial Sequence Number)揭斧,以便讓對方知道接下來接收數(shù)據(jù)的時候如何按序列號組裝數(shù)據(jù)。如果 ISN 是固定的峻堰,攻擊者很容易猜出后續(xù)的確認號讹开,因此 ISN 是動態(tài)生成的。

三次握手過程中可以攜帶數(shù)據(jù)嗎捐名?

其實第三次握手的時候旦万,是可以攜帶數(shù)據(jù)的。但是镶蹋,第一次成艘、第二次握手不可以攜帶數(shù)據(jù)

為什么這樣呢?大家可以想一個問題,假如第一次握手可以攜帶數(shù)據(jù)的話贺归,如果有人要惡意攻擊服務器淆两,那他每次都在第一次握手中的 SYN 報文中放入大量的數(shù)據(jù)。因為攻擊者根本就不理服務器的接收拂酣、發(fā)送能力是否正常秋冰,然后瘋狂著重復發(fā) SYN 報文的話,這會讓服務器花費很多時間婶熬、內存空間來接收這些報文剑勾。

也就是說埃撵,第一次握手不可以放數(shù)據(jù),其中一個簡單的原因就是會讓服務器更加容易受到攻擊了虽另。而對于第三次的話暂刘,此時客戶端已經(jīng)處于 ESTABLISHED 狀態(tài)。對于客戶端來說洲赵,他已經(jīng)建立起連接了鸳惯,并且也已經(jīng)知道服務器的接收商蕴、發(fā)送能力是正常的了叠萍,所以能攜帶數(shù)據(jù)也沒啥毛病。

SYN攻擊是什么绪商?

服務器端的資源分配是在二次握手時分配的苛谷,而客戶端的資源是在完成三次握手時分配的,所以服務器容易受到SYN洪泛攻擊格郁。SYN攻擊就是Client在短時間內偽造大量不存在的IP地址腹殿,并向Server不斷地發(fā)送SYN包,Server則回復確認包例书,并等待Client確認锣尉,由于源地址不存在,因此Server需要不斷重發(fā)直至超時决采,這些偽造的SYN包將長時間占用未連接隊列自沧,導致正常的SYN請求因為隊列滿而被丟棄,從而引起網(wǎng)絡擁塞甚至系統(tǒng)癱瘓树瞭。SYN 攻擊是一種典型的 DoS/DDoS 攻擊拇厢。

檢測 SYN 攻擊非常的方便,當你在服務器上看到大量的半連接狀態(tài)時晒喷,特別是源IP地址是隨機的孝偎,基本上可以斷定這是一次SYN攻擊。在 Linux/Unix 上可以使用系統(tǒng)自帶的 netstats 命令來檢測 SYN 攻擊凉敲。

netstat -n -p TCP | grep SYN_RECV

常見的防御 SYN 攻擊的方法有如下幾種:

  • 縮短超時(SYN Timeout)時間
  • 增加最大半連接數(shù)
  • 過濾網(wǎng)關防護
  • SYN cookies技術

四次揮手

建立一個連接需要三次握手衣盾,而終止一個連接要經(jīng)過四次揮手(也有將四次揮手叫做四次握手的)。這由TCP的半關閉(half-close)造成的爷抓。所謂的半關閉势决,其實就是TCP提供了連接的一端在結束它的發(fā)送后還能接收來自另一端數(shù)據(jù)的能力。

TCP 的連接的拆除需要發(fā)送四個包废赞,因此稱為四次揮手(Four-way handshake)徽龟,客戶端或服務器均可主動發(fā)起揮手動作。

剛開始雙方都處于 ESTABLISHED 狀態(tài)唉地,假如是客戶端先發(fā)起關閉請求据悔。四次揮手的過程如下:

  • 第一次揮手:客戶端發(fā)送一個 FIN 報文传透,報文中會指定一個序列號。此時客戶端處于 FIN_WAIT1 狀態(tài)极颓。 即發(fā)出連接釋放報文段(FIN=1朱盐,序號seq=u),并停止再發(fā)送數(shù)據(jù)菠隆,主動關閉TCP連接兵琳,進入FIN_WAIT1(終止等待1)狀態(tài),等待服務端的確認骇径。
  • 第二次揮手:服務端收到 FIN 之后躯肌,會發(fā)送 ACK 報文,且把客戶端的序列號值 +1 作為 ACK 報文的序列號值破衔,表明已經(jīng)收到客戶端的報文了清女,此時服務端處于 CLOSE_WAIT 狀態(tài)。 即服務端收到連接釋放報文段后即發(fā)出確認報文段(ACK=1晰筛,確認號ack=u+1嫡丙,序號seq=v),服務端進入CLOSE_WAIT(關閉等待)狀態(tài)读第,此時的TCP處于半關閉狀態(tài)曙博,客戶端到服務端的連接釋放×鳎客戶端收到服務端的確認后父泳,進入FIN_WAIT2(終止等待2)狀態(tài),等待服務端發(fā)出的連接釋放報文段盼砍。
  • 第三次揮手:如果服務端也想斷開連接了尘吗,和客戶端的第一次揮手一樣,發(fā)給 FIN 報文浇坐,且指定一個序列號睬捶。此時服務端處于 LAST_ACK 的狀態(tài)。即服務端沒有要向客戶端發(fā)出的數(shù)據(jù)近刘,服務端發(fā)出連接釋放報文段(FIN=1擒贸,ACK=1,序號seq=w觉渴,確認號ack=u+1)介劫,服務端進入LAST_ACK(最后確認)狀態(tài),等待客戶端的確認案淋。
  • 第四次揮手:客戶端收到 FIN 之后座韵,一樣發(fā)送一個 ACK 報文作為應答,且把服務端的序列號值 +1 作為自己 ACK 報文的序列號值,此時客戶端處于 TIME_WAIT 狀態(tài)誉碴。需要過一陣子以確保服務端收到自己的 ACK 報文之后才會進入 CLOSED 狀態(tài)宦棺,服務端收到 ACK 報文之后,就處于關閉連接了黔帕,處于 CLOSED 狀態(tài)代咸。 即客戶端收到服務端的連接釋放報文段后,對此發(fā)出確認報文段(ACK=1成黄,seq=u+1呐芥,ack=w+1),客戶端進入TIME_WAIT(時間等待)狀態(tài)奋岁。此時TCP未釋放掉思瘟,需要經(jīng)過時間等待計時器設置的時間2MSL后,客戶端才進入CLOSED狀態(tài)厦取。

收到一個FIN只意味著在這一方向上沒有數(shù)據(jù)流動潮太」芴拢客戶端執(zhí)行主動關閉并進入TIME_WAIT是正常的虾攻,服務端通常執(zhí)行被動關閉,不會進入TIME_WAIT狀態(tài)更鲁。

在socket編程中霎箍,任何一方執(zhí)行close()操作即可產(chǎn)生揮手操作。

揮手為什么需要四次澡为?

因為當服務端收到客戶端的SYN連接請求報文后漂坏,可以直接發(fā)送SYN+ACK報文。其中ACK報文是用來應答的媒至,SYN報文是用來同步的顶别。但是關閉連接時,當服務端收到FIN報文時拒啰,很可能并不會立即關閉SOCKET驯绎,所以只能先回復一個ACK報文,告訴客戶端谋旦,"你發(fā)的FIN報文我收到了"剩失。只有等到我服務端所有的報文都發(fā)送完了,我才能發(fā)送FIN報文册着,因此不能一起發(fā)送拴孤。故需要四次揮手。

2MSL等待狀態(tài)

TIME_WAIT狀態(tài)也成為2MSL等待狀態(tài)甲捏。每個具體TCP實現(xiàn)必須選擇一個報文段最大生存時間MSL(Maximum Segment Lifetime)演熟,它是任何報文段被丟棄前在網(wǎng)絡內的最長時間。這個時間是有限的司顿,因為TCP報文段以IP數(shù)據(jù)報在網(wǎng)絡內傳輸芒粹,而IP數(shù)據(jù)報則有限制其生存時間的TTL字段蚕冬。

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

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

四次揮手釋放連接時,等待2MSL的意義?

為了保證客戶端發(fā)送的最后一個ACK報文段能夠到達服務器贞谓。因為這個ACK有可能丟失限佩,從而導致處在LAST-ACK狀態(tài)的服務器收不到對FIN-ACK的確認報文。服務器會超時重傳這個FIN-ACK裸弦,接著客戶端再重傳一次確認祟同,重新啟動時間等待計時器。最后客戶端和服務器都能正常的關閉理疙。假設客戶端不等待2MSL晕城,而是在發(fā)送完ACK之后直接釋放關閉,一但這個ACK丟失的話窖贤,服務器就無法正常的進入關閉連接狀態(tài)砖顷。

兩個理由:

  1. 保證客戶端發(fā)送的最后一個ACK報文段能夠到達服務端。 這個ACK報文段有可能丟失赃梧,使得處于LAST-ACK狀態(tài)的B收不到對已發(fā)送的FIN+ACK報文段的確認滤蝠,服務端超時重傳FIN+ACK報文段,而客戶端能在2MSL時間內收到這個重傳的FIN+ACK報文段授嘀,接著客戶端重傳一次確認物咳,重新啟動2MSL計時器,最后客戶端和服務端都進入到CLOSED狀態(tài)粤攒,若客戶端在TIME-WAIT狀態(tài)不等待一段時間所森,而是發(fā)送完ACK報文段后立即釋放連接,則無法收到服務端重傳的FIN+ACK報文段夯接,所以不會再發(fā)送一次確認報文段甩栈,則服務端無法正常進入到CLOSED狀態(tài)勒葱。

  2. 防止“已失效的連接請求報文段”出現(xiàn)在本連接中。 客戶端在發(fā)送完最后一個ACK報文段后,再經(jīng)過2MSL雕憔,就可以使本連接持續(xù)的時間內所產(chǎn)生的所有報文段都從網(wǎng)絡中消失,使下一個新的連接中不會出現(xiàn)這種舊的連接請求報文段。

time_wait過多

這種情況比較常見,一般會出現(xiàn)在爬蟲服務器和web服務器(如果沒做內核參數(shù)優(yōu)化的話)上际邻,那么這種問題是怎么產(chǎn)生的呢?

time_wait是主動關閉連接的一方保持的狀態(tài)芍阎,對于爬蟲服務器來說它自身就是客戶端世曾,在完成一個爬取任務后就會發(fā)起主動關閉連接,從而進入time_wait狀態(tài)谴咸,然后保持這個狀態(tài)2MSL時間之后轮听,徹底關閉回收資源。這里為什么會保持資源2MSL時間呢岭佳?這也是TCP/IP設計者規(guī)定的血巍。

time_wait問題可以通過調整內核參數(shù)和適當?shù)脑O置web服務器的keep-Alive值來解決。

close_wait過多

close_wait狀態(tài)出現(xiàn)的原因是被動關閉方未關閉socket造成珊随。

快速的解決方法是:

  • 關閉正在運行的程序述寡,這個需要視業(yè)務情況而定。
  • 盡快的修改程序里的bug叶洞,然后測試提交到線上服務器鲫凶。

總結

《TCP/IP詳解 卷1:協(xié)議》有一張TCP狀態(tài)變遷圖,很具有代表性京办,有助于大家理解三次握手和四次揮手的狀態(tài)變化掀序。如下圖所示,粗的實線箭頭表示正常的客戶端狀態(tài)變遷惭婿,粗的虛線箭頭表示正常的服務器狀態(tài)變遷。

Linux系統(tǒng)中分給每個用戶的文件句柄數(shù)是有限的叶雹,而TIME_WAIT和CLOSE_WAIT這兩種狀態(tài)如果一直被保持财饥,那么意味著對應數(shù)目的通道(此處應理解為socket,一般一個socket會占用服務器端一個端口折晦,服務器端的端口最大數(shù)是65535)一直被占用钥星,一旦達到了上限,則新的請求就無法被處理满着,接著就是大量Too Many Open Files異常

參考文獻

https://juejin.im/post/5d9c284b518825095879e7a5

http://www.reibang.com/p/394cafc91d18

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末谦炒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子风喇,更是在濱河造成了極大的恐慌宁改,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魂莫,死亡現(xiàn)場離奇詭異还蹲,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門谜喊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來潭兽,“玉大人,你說我怎么就攤上這事斗遏∩截裕” “怎么了?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵诵次,是天一觀的道長怒坯。 經(jīng)常有香客問我,道長藻懒,這世上最難降的妖魔是什么剔猿? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮嬉荆,結果婚禮上归敬,老公的妹妹穿的比我還像新娘。我一直安慰自己鄙早,他們只是感情好汪茧,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著限番,像睡著了一般舱污。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上弥虐,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天扩灯,我揣著相機與錄音,去河邊找鬼霜瘪。 笑死珠插,一個胖子當著我的面吹牛,可吹牛的內容都是我干的颖对。 我是一名探鬼主播捻撑,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缤底!你這毒婦竟也來了顾患?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤个唧,失蹤者是張志新(化名)和其女友劉穎江解,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坑鱼,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡膘流,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年絮缅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呼股。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡耕魄,死狀恐怖,靈堂內的尸體忽然破棺而出彭谁,到底是詐尸還是另有隱情吸奴,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布缠局,位于F島的核電站则奥,受9級特大地震影響,放射性物質發(fā)生泄漏狭园。R本人自食惡果不足惜读处,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望唱矛。 院中可真熱鬧罚舱,春花似錦、人聲如沸绎谦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窃肠。三九已至包个,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冤留,已是汗流浹背碧囊。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留搀菩,地道東北人呕臂。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像肪跋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子土砂,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內容