1. 程式人生 > >Linux入門真經-047TCP會話的建立與斷開

Linux入門真經-047TCP會話的建立與斷開

敲!黑!板!無論是大學計算機網路期末考試,還是網路/運維/技術支援乃至程式猿面試,這個問題都命中率極高。本篇文章會介紹TCP連線的建立與斷開以及一些常用的TCP引數,不過,僅限於入門知識哈。

1、TCP頭中的重要引數

seq與len:

TCP的傳輸是有序的,它為每一個數據段都標上了一個序號。因為傳輸距離的遙遠和網路的龐大和複雜,先發出去的包未必就能先到達目的地,因此資料段亂序時有發生,甚至某些資料會在傳輸過程中丟失。有了序號,目的端可以根據序號進行排序,當發現中間缺少部分資料的時候,只需要請求傳送端重傳這一小段資料就可以了。

seq就表示了資料段的序號,而len表明了資料段的長度。比如我們傳送了一個數據段,seq=1,len=1448,如果後面還有資料,那麼第二個包的seq應當是1+1448=1449,也就是說,下一個資料段的seq號等於上一個資料段的seq+len。你可以比照一下下圖

TCP是雙向的。在一個連線中,雙方都可以是傳送方。因此各自維護了一組seq號碼。

另外補充一點,len的長度是可以為0的,len不包括TCP頭的長度,很多維護會話性質的資料段的len就是0,而TCP的頭部其實包含了很多資訊。

ack:確認號。它告訴傳送方已經收到了一些資訊,並希望傳送方下一次傳送哪些位元組。ack號的數值就是期望下一次傳送方傳送資料段的seq值。

比如甲和乙建立了TCP連線後,甲傳送了一個數據段的seq=x,len=y;那麼乙回覆的時候ack=x+y,表示它收到了x+y之前的所有位元組,並期望甲傳送seq=x+y的資料段。

同理,由於tcp連線的兩端都能是傳送方,因此他們各自維護自己的ack號。

試圖理解下面這個例子以確認你理解了seq、len、和ack這三個引數。

甲和乙建立起了TCP連線。乙依次收到了下面幾個資料包,seq和len的值分別是:

seq=1000,len=100

seq=500,len=100

seq=600,len=100

乙根據seq排序之後順序如下:

seq=500,len=100

seq=600,len=100

seq=1000,len=100

排序完成後,發現seq=600,len=100之後後面收到的seq=1000,判斷中間少了些什麼資料,所以它回覆了一個數據包,tcp頭部中的ack=700,希望甲可以重傳seq=700的包。

好的,接下來我們再來看幾個關於建立和斷開連線的引數:SYN、FIN、RST

這幾個位,包括剛剛介紹的ACK,都位於TCP的FLAG欄位中,有著不同的含義,比如,ACK位置1則表示這個資料段包含了ACK資訊。

當然,FLAG欄位中還有一些其他的位,表示了不同的含義,接下來介紹常見的SYN、FIN、和RST

SYN:攜帶這個標誌位表示希望能夠發起一個TCP連線請求,有點像打電話的時候,雙方都會先說一句:“喂”。

FIN:表示有一方希望能夠正常地終止請求。

RST:用於重置連線,或者拒絕請求。

TCP通訊藉助於計算機的埠。接入網路的計算機往往會同時有幾十上百個TCP連線,不同的應用層協議會監聽在不同的埠之上,計算機根據所收到資料段的目的埠,將資料傳送給不同的應用層協議處理。傳送TCP資料的時候要指明目的埠在哪裡,目的主機才知道把資料給哪個應用程式;同時TCP頭中也會包含源埠,方便接收端回覆資料時,回覆的資料能夠抵達傳送端對應的應用程式。

比如下面這個資料段,源埠就是傳送端主機的44208埠,目的埠就是接收端的54321埠

下面附上一個TCP頭部結構圖,你可以參考比照上面wireshark中TCP欄位的結構內容。

2、三次握手與四次揮手

好的,讓我們來了解一下TCP會話的建立過程

建立連線時,一定是某一方先發起請求,假設發起請求的是client端(事實上也通常如此),client先發送一個SYN置1的包,表示想要建立連線。傳送完畢後client端就處於SYN_SENT狀態;

server在收到SYN包之前處於listen狀態,監聽在某一埠等待連線的到來;

server收到後SYN包,傳送ack表示收到了這個包,同時在資料段中將SYN位也置1。傳送後server處於SYN_RCVD狀態。

當client收到server發出的這個包之後,會發送ack表示自己收到了這個包,client將自己置為ESTABLISHED狀態,此時三次握手完成,開始傳輸資料。

三次握手過程如下圖

如下圖就是一個三次握手的報文示例,它是TCP會話的開端,如下圖,完成會話後,客戶端就向伺服器提出了GET / HTTP/1.1的請求,然後伺服器開始向客戶端傳輸資料。

一次TCP會話可以傳輸多個資源,比如本次客戶端請求/ HTTP/1.1的資源之後,它還能夠請求/_static/jquery.js HTTP/1.1\r\n;或者圖片、動畫等資源,都能在本次TCP會話中進行傳輸。

TCP四次揮手

天下沒有不散的宴席,TCP會話有建立就有終止。

仍然借用之前的例子,假設client現在要終止會話。(任何一端都可以終止會話)

client傳送一個FIN置1的資料段表明自己要斷開連線。傳送完畢後自己則處於FIN_WAIT_1狀態

server收到這個包之後,將自己置於CLOSE_WAIT狀態,接著他會向client傳送兩個包,一個是ack包,宣告剛剛那個包自己已經收到,一個是FIN包,因為TCP連線是雙向的,己方也要請求中斷連線。發完這兩個包之後server端處於LAST_ACK狀態。

client收到server發來的FIN包之後,傳送ack包表示已經收到,將自己置於TIME-WAIT狀態,等待一段時間後關閉會話。

Server收到client發來的ack包之後,關閉會話。

整個過程整理如下圖。

並不是所有的TCP會話都會正常地結束,有時會使用RST標誌來終止會話。收到RST置1的資料包之後,不會有任何的後續,連線直接關閉。導致RST的原因有很多,客戶端關閉、服務端拒絕連線、防止惡意掃描、軟體崩潰等等都可能導致RST的發生。

比如下面這個示例,客戶端傳送FIN,ACK請求終止連線,重傳了數次仍然沒有收到任何迴應,最後客戶端用RST重置了連線。

3、一些拓展性問題

TCP協議是一個經久不衰的話題。會話的建立和斷開只是和TCP相關的一個很小的知識點。還有很多有意思、有深度的周邊話題值得你去了解。你還可以深入地瞭解一下TCP的重傳機制、延遲確認機制、滑動視窗機制、慢啟動、擁塞避免方法等。這些東西對新手並不友好,而且一些細節很容易遺忘。但是瞭解這些內容很有必要,建議做好筆記,讓自己有個印象。這樣遇到一些故障或者效能問題時,你可能會更有頭緒。

下一章為大家解釋跨網段通訊是如何進行的,以及NAT地址轉換技術。下下章為大家介紹IPV6協議,它的出現旨在解決IPV4地址不夠的問題。再接下來我們會回到Linux系統,介紹一系列關於網路的命令與引數。

關注本公眾號獲取最新更新(公眾號名:linux入門真經)

每週一、三、五穩定更新