三十天學不會TCP,UDP/IP網絡編程 - RST的用法

不知不覺也寫了這麼多了,繼續個人本身的推廣大業~完整版能夠去gitbook(https://rogerzhu.gitbooks.io/-tcp-udp-ip/content/)看到。git

若是對和程序員有關的計算機網絡知識,和對計算機網絡方面的編程有興趣,雖說如今這種「看不見」的東西真正能在實用中遇到的機會很少,可是我始終以爲不管計算機的語言,熱點方向怎麼變化,做爲一個程序員,不少基本的知識都應該有所瞭解。而當時在網上搜索資料的時候,這方面的資料真的是少的可憐,因此,我有幸前兩年接觸了這方面的知識,我以爲我應該把我知道的記錄下來,雖然寫的不必定很好,可是但願能給須要幫助的人多個參考。個人計劃是用半年時間來寫完這一系列文章,這個標題也是我對太多速成文章的一種態度,好了,廢話再也不多扯了,下面是其中的一節內容,更多內容能夠去gitbook上找到。程序員

TCP的六個標識符裏,有一個表明RST,reset,可是翻譯成重置鏈接彷佛也不太穩當,報告錯誤也不太合適,做爲一個優雅而又邏輯合理的協議,RST對於TCP中出現的錯誤而致使兩端都進入錯誤處理有重要的做用。面試

狀況沒有按照預想的進行

有句詩叫作「不如意事常八九,能與人言無二三」,做爲一個龐大,複雜,系統的協議,TCP通訊中常常都會出現不是一路順風的狀況。好比前面提過,在三次握手的第二階段,若是在幾回重發都失敗的狀況下,會回覆一個RST包。正是TCP有這個設計才能讓TCP稱得上連失敗了都處理的很優雅。編程

爲何要有這麼一個RST包而不是在結束的時候直接粗暴的結束或者說啥也不發生的結束呢?仍是先讓咱們看看現實中打電話的例子,現實中總有那種媽媽給本身的兒子女兒打電話,兒子女兒不耐煩的,甚至產生衝突。而這個時候若是兒女這一端簡單的把電話放下,媽媽那一端就只能聽到環境聲,對於這邊的狀況徹底不瞭解。先不說這種對於對端極不禮貌的作法,至少這樣讓對端感到很擔憂,不知道那一邊是怎麼狀況。而即便你再生氣可是你說,不說了,不說了,我掛了,而後掛上電話,哪怕是很重的摔下電話。至少對端能夠從嘟嘟聲中知道對端已經掛了電話,不用擔憂前面描述的那種擔憂了。服務器

TCP也是同樣,若是沒有這個RST包,那麼出現出現異常的對端只能等待,由於他根本可能知道對端怎麼了。在資源極端重要的網絡環境裏,這樣的作法不只浪費資源更重要的是讓TCP這種號稱核彈都炸不毀的協議陷入了一種混沌的狀態,就像C/C++中的野指針同樣,沒法管理無序而又混亂。RST包幾乎涵蓋在TCP每一個狀態中,下面在介紹何時會發送RST包以前,先得了解一下正常的狀態下的TCP各類狀態變遷,這有了解了正常才能更好理解異常嘛。網絡

TCP狀態變遷圖

我一直認爲在計算機領域,有兩個狀態機圖最經典,一個是進程調度時候的進程狀態變遷圖,第二個就是TCP狀態變遷圖了。這個圖清晰的表示了在使用TCP協議通訊時,從創建鏈接到釋放鏈接的每一個過程,若是你能不靠任何外力的狀況下畫出這張圖,那麼不得不說你已經對TCP的每一個階段瞭如執掌了,若是再理解下TCP中的流量控制等等,那麼其實關於這方面的面試你徹底不用擔憂了。tcp

廢話很少說了,我從網上挑了一張我以爲我看着最舒服的版本:spa

 

這上面的全部狀態在前面兩節都說過了,除了Established狀態,這個狀態表示TCP處於鏈接傳輸數據的狀態,算是一個比較穩定的狀態。相比於創建鏈接和終止鏈接,這個狀態在狀態自己上並無什麼特別的,就像一條路修完以後,車子就上去跑就好了。可是在鏈接狀態下,TCP的太多設計哲學就蘊含在這裏面了,咱們現實中的道路管理要能借鑑裏面的一些思想,不少擁堵狀況都能避免了。計算機網絡

 

言歸正傳,在這個圖中,狀態不少,爲了演示下怎麼樣去看這種狀態機狀態圖,我就敘述下怎麼樣從這個圖中找到三次握手中的種種狀態變遷。翻譯

狀態機圖主要有兩個部分組成,框框表示某種狀態,框框之間用線條鏈接,標識狀態的變遷,而在這些線條之上每每會寫着一些說明,這些說明被譽爲激勵條件,一個狀態只有通過了某種條件的刺激或者激勵才能變遷爲另外一個狀態。打個比方吧,好比你在發呆,你處於空閒狀態,這個時候我打你一下,給你一個刺激,你就會從空閒狀態變遷爲疼痛狀態了。

全部的狀態都從Closed開始,在這個圖的敘述中,有兩條說明,實現表示客戶,虛線表示服務器,準確的來講,這種說法並不嚴謹,由於在TCP的通訊過程當中其實沒有服務器和客戶之分,兩邊都在同等的發送數據。而在這個圖或者通常的表述中,主動發起鏈接的那一方通常會被稱之爲客戶端,被動接受的那一段是服務器端。在瞭解了這些先決條件以後,那麼就來一塊兒找找這個圖中的三次握手在哪裏吧。

首先看Closed狀態中的實線,也就是表示客戶的狀態,在右邊,主動發送SYN以後,進入SYN_SENT狀態,三次握手第一步完成。而在這以後,收到SYN和ACK包,而後發送ACK以後客戶這邊就進入了鏈接狀態。

而後再看看另外一條路,從Closed狀態虛線進入listen狀態,這裏不須要任何激勵條件就能完成,由於默認服務器一直在監聽客戶發來的請求,否則那你這個圖就畫不下去了。在收到SYN,發送SYN和ACK以後進入SYN_RCVD狀態,也就是三次握手的第二步。而後就是繼續收到對端的ACK以後,進入鏈接狀態。

每一個狀態機圖都能很方便的變成不少獨立的小單元,這也是一個狀態機圖繪畫的好與很差的一個標誌。好的狀態機圖狀態之間變遷關係清晰,彼此耦合性很小。而差的你就感受在這種狀態變化的指示下只會變成一團混亂。

仔細看一下這個狀態機圖,你會發現不少前面並無說起的有趣的狀態,他們中不少都是很邊緣的狀況,可是做爲一個嚴謹的協議設計者,應該最大可能留下最小的漏洞。好比圖中你會發現從listen狀態能夠直接變成SYN_SEND狀態,回想一下前面說了服務器端會默認爲是listen狀態從而能夠監聽對端來的請求。可是若是這個時候服務器端主動發送了SYN,那麼他其實就是咱們定義中的「客戶」了,因此圖中用實線標識這種狀況下會SYN_SEND狀態。

另一個在發起鏈接階段的時候的特殊狀況就是SYN_SEND和SYN_RCVD中間那條線,若是一個客戶在進入SYN_SEND同時收到對端發送回來的SYN請求,通俗點說就是兩端同時發起了鏈接,兩邊都是客戶了,這個時候TCP不會就此終止,而是進入SYN_RCVD,而後再經歷後面的過程以後,兩邊都進入了Established狀態。

這就是這張圖的上半部分,若是有興趣能夠看看下半部分整個的關閉流程做爲聯繫。

RST狀態變遷圖

在瞭解了正常狀態變遷以後,異常狀態就不會顯得特別的亂了,在網上我找到了這麼一張圖,我以爲畫的特別好,就拿來借用了。

 

 

對比上面的圖,這張圖用紅色的部分標識了發送RST的狀況,可是也簡化了一些上面有的狀態變遷,不過這對於瞭解整個TCP過程當中RST的狀態變遷沒有那麼重要了。

從這個圖中第一個能夠學到的知識就是經歷全部RST狀態以後,鏈接都會進入Closed狀態,也就是結束。RST的狀態基本分紅兩種,超時和包丟失。

首先看看超時的狀況,在圖中就三種包重傳超時,SYN,FIN和數據包,能夠看到超時都是某種「主動的動做」。好比在三次握手的第二個階段,重傳SYN+ACK一直超時,服務器端就只能發送一個RST到對端了。同理在FIN超時和自己傳輸數據超時以後,RST也會發送到對方。

第二類是丟失,其實本質上上和上一種狀況是一直的,在ACK丟失的狀況下,在對端看來就是發送包超時,因此在這種狀況下主要是接收RST。

那麼在現實生活中,什麼樣的狀況會致使超時呢?其實不少狀況均可能發生,好比某一端程序忽然崩潰,某一端忽然沒電了等等,這種狀況下都會引發超時,從而會致使RST包的發送。若是用官方的語言總結下,RST包會在如下三種狀況下被髮送:

到達的端口不存在,好比說在客戶端發送SYNC想創建鏈接的時候,對端並無任何監聽端口,那麼就會發生超時,從而發送RST包。而在UDP這種沒有鏈接的協議中,一個ICMP端口不可達消息就能解決這個問題(若是你對這些名詞很陌生,能夠看看前面的文章了)。

鏈接被異常終止, 好比說應用程序崩潰了。

檢測半關閉鏈接,這個半關閉的概念其實在上一篇的時候有所說起,可是不詳細,這裏正好說明一下。半關閉鏈接主要發生在某一段已經關閉或者異常終止可是另一段並不知道的狀況下。好比在通訊的過程當中,忽然拔掉服務器那邊的網線,而後再重啓服務器和其應用程序。這個時候鏈接就處於一個半關閉狀態,此時客戶機再向對方發一個消息,服務器端會回覆一個RST消息,本端就知道剛纔發生了什麼。

說了這麼多,言而總之其實RST主要做用有兩個,報告本端異常,告知對方錯誤,記住這兩句話就差很少記住了RST包的做用。

相關文章
相關標籤/搜索