文章轉自 http://network.51cto.com/art/201409/452808_all.htm 若有轉載,請註明出處
安全
TCP通訊最重要的特徵是:有序(ordering)和可靠(reliable)。有序是經過將文本流分段並編號實現的。可靠是經過ACK回覆和重複發送(retransmission)實現的。這一篇文章將引入TCP鏈接(connection)的概念。服務器
TCP鏈接網絡
網絡層在邏輯上提供了端口的概念。一個IP地址能夠有多個端口。一個具體的端口須要IP地址和端口號共同肯定(咱們記爲IP:port的形式)。一 個鏈接爲兩個IP:port之間創建TCP通訊。(一個經常使用的比喻爲:TCP鏈接就像兩我的打電話, IP爲總機號碼,port爲分機號碼)併發
參與鏈接的若是是兩臺電腦,那麼兩臺電腦操做系統的TCP模塊負責創建鏈接。每一個鏈接有四個參數(兩個IP,兩個端口),來代表「誰在和誰通話」。 每臺電腦都會記錄有這四個參數,以肯定是哪個鏈接。若是這四個參數徹底相同,則爲同一鏈接;若是這四個參數有一個不一樣,即爲不一樣的鏈接。這意味着,同一 個端口上能夠有多個鏈接。內核中的TCP模塊生成鏈接以後,將鏈接分配給進程使用。 ide
一個端口上能夠有多個鏈接spa
TCP鏈接是雙向(duplex)的。在TCP協議與"流"通訊中,咱們所展現的TCP傳輸是單向的。雙向鏈接實際上就是創建兩個方向的TCP傳 輸,因此概念上並不複雜。這時,鏈接的每一方都須要兩個滑窗,以分別處理髮送的文本流和接收的文本流。因爲鏈接的雙向性,咱們也要爲兩個方向的文本流編 號。這兩個文本流的編號相互獨立。爲文本流分段和編號由發送方來處理,回覆ACK則由接收的一方進行。操作系統
TCP片斷的頭部格式3d
在深刻TCP鏈接以前,咱們須要對TCP片斷的頭部格式有一些瞭解。咱們知道,TCP片斷分爲頭部和數據。數據部分爲TCP真正傳輸的文本流數據。下面爲TCP片斷的頭部格式:server
來自wikipediahtm
先關注下面幾點:
1. 一個TCP頭部須要包含出發端口(source port)和目的地端口(destination port)。這些與IP頭中的兩個IP地址共同肯定了鏈接。
2. 每一個TCP片斷都有序號(sequence number)。這些序號最終將數據部分的文本片斷整理成爲文本流。
3. ACK是一位(bit)。只有ACK位設定的時候,回覆號(Acknowledgement number)纔有效。ACK回覆號說明了接收方期待接收的下一個片斷,因此ACK回覆號爲最後接收到的片斷序號加1。
不少時候,ACK回覆「附着」在發送的數據片斷中。TCP協議是雙向的。好比A和B兩個電腦。ACK回覆是接收方回覆給發送方 (好比A發送給B, B回覆A)。但同時,B也能夠是發送方,B有可能有數據發送給A,因此B就把ACK回覆附着在它要發送給A的數據片斷的頭部。這樣能夠減小ACK所佔用的 交通流量。一個片斷能夠只包含ACK回覆。一個純粹的ACK回覆片斷不傳送文本流,因此不消耗序列號。若是有下一個正常的數據片斷,它的序號將與純粹 ACK回覆片斷的序號相同。
(ACK回覆還能夠「附着」在SYN片斷和FIN片斷)
4. ACK後面還有SYN和FIN,它們也各佔據一位(bit)。我將在後面說明這兩位。
鏈接的創建
在TCP協議與"流"通訊中討論的TCP傳輸須要一個前提:TCP鏈接已經創建。然而,TCP鏈接從無到有須要一個創建鏈接的過程。創建鏈接的最重 要目是讓鏈接的雙方交換初始序號(ISN, Initial Sequence Number)。根據TCP協議的規定,文本流的第一個片斷的序號不能是肯定的數字(好比說1)。鏈接的雙方各自隨機生成本身的ISN,而後再利用的必定 方式讓對方瞭解。這樣的規定是出於TCP鏈接安全考慮:若是以一個肯定的數字做爲初始的TCP序號,那麼其餘人很容易猜出接下來的序列號,並按照正確的序 號發送「假裝」的TCP片斷,以插入到文本流中。
ISN交換是經過SYN片斷實現的。SYN片斷由頭部的SYN位代表,它的序號爲發送方的ISN。該片斷由鏈接的一方首先發給給另外一方,咱們將發送 SYN的一方稱爲客戶(client),而接收SYN的一方稱爲服務器(server)。咱們使用ISN(c)表示client一方的ISN,使用 ISN(s)表示server一方的ISN。隨後,接收到SYN的server須要回覆ACK,併發送出包含有server的ISN的SYN片斷。下圖爲 創建鏈接的過程,也就是經典的TCP三次握手(three-way handshaking)。兩條豎直線分別爲client和server的時間軸。每一個箭頭表明了一次TCP片斷的單向傳輸。
青色爲純粹的ACK片斷。整個過程的本質是雙方互發含有本身的ISN的SYN片斷。根據TCP傳輸的規則,接收到ISN的一方須要回覆ACK,因此 共計四片信息在創建鏈接過程當中傳輸。之因此是三次握手 (而不是四次),是由於server將發送SYN和回覆ACK合併到一個TCP片斷中。咱們以client方爲例。client知道本身的ISN(也就是 ISN(c))。創建鏈接以後,它也知道了對方的ISN(s)。此後,若是須要發送文本流片斷,則編號爲ISN(c) + 1, ISN(c) + 2 ...。若是接收文本流片斷,則期待接收ISN(s) + 1, ISN(s) + 2 ...。
鏈接創建以後,鏈接的雙方就能夠按照TCP傳輸的方式相互發送文本流了。
鏈接的正常終結
一個鏈接創建以後,鏈接兩端的進程能夠利用該鏈接進行通訊。當鏈接的一方以爲「我講完了」,它能夠終結鏈接中發送到對方方向的通訊。鏈接最終經過四次握手(four-way handshaking)的方式終結,鏈接終結使用的是特殊片斷FIN(FIN位爲1的片斷)。
咱們能夠看到,鏈接終結的過程當中,鏈接雙方也交換了四片信息(兩個FIN和兩個ACK)。在終結鏈接的過程當中,TCP並無合併FIN與ACK片 段。緣由是TCP鏈接容許單向關閉(half-close)。也就是說,TCP鏈接關閉了一個方向的傳輸,成爲一個單向鏈接(half-duplex)。 第二個箭頭和第三個箭頭傳遞必須分開,纔能有空隙在開放的方向上繼續傳輸。若是第二個箭頭和第三個箭頭合併在一塊兒,那麼,隨着一方關閉,另外一方也要被迫關 閉。
第二和第三次握手之間,server能夠繼續單向的發送片斷給client,但client不能發送數據片斷給server。
(上面的終結從client先發起,TCP鏈接終結也能夠從server先發起。)
在Client發送出最後的ACK回覆,但該ACK可能丟失。Server若是沒有收到ACK,將不斷重複發送FIN片斷。因此Client不能立 即關閉,它必須確認Server接收到了該ACK。Client會在發送出ACK以後進入到TIME_WAIT狀態。Client會設置一個計時器,等待 2MSL的時間。若是在該時間內再次收到FIN,那麼Client會重發ACK並再次等待2MSL。所謂的2MSL是兩倍的MSL(Maximum Segment Lifetime)。MSL指一個片斷在網絡中最大的存活時間,2MSL就是一個發送和一個回覆所需的最大時間。若是直到2MSL,Client都沒有再 次收到FIN,那麼Client推斷ACK已經被成功接收,則結束TCP鏈接。
TIME_WAIT State
總結
TCP是鏈接導向的協議,與之對應的是像UDP這樣的非鏈接導向的協議。鏈接能帶來更好的傳輸控制,但也須要更多額外的工做,好比鏈接的創建和終結。
咱們還初步瞭解了TCP的頭部格式。應該注意到,許多時候咱們將ACK片斷「附着」在其餘片斷上。相對於純粹的ACK片斷,咱們這樣作節約了ACK 所需的流量。事實上,因爲ACK片斷所需的ACK位和acknowledge number區域老是存在於TCP的頭部,因此附着ACK片斷的成本基本上等於0。