在學習的過程中,相信大家都有過“學了就忘“這種經歷,又特別是TCP/IP知識點密集的通信協議,所以在此總結一下自己學到的皮毛,希望對自己對大家也有所幫助。
這篇博客主要講運輸層TCP和UDP的東西,IP層以后有時間再來補充。
TCP
TCP的全稱叫傳輸控制協議(Transmission Control Protocol),這個協議的目的就是為網絡數據提供可靠的運輸服務。
tcp5個特點:
1) 面向連接。應用程序在使用TCP協議之前,必須先建立TCP連接(三次握手)。數據傳輸完畢后,必須釋放連接。
2)每一條TCP連接只能有兩個端點。
3)提供可靠交付的服務。通過TCP連接傳送的數據,無差錯、不丟失、不重復、並且按序到達。(其實我們很多web服務也是要求可靠的,所以服務在應用層的設計是不是可以參考TCP的協議的設計?)
4)全雙工通信。通信雙方任何時候都能發送數據。
這里面有個重點就是兩端都設有發送緩存和接收緩存(在內核中),用來臨時存放雙向通信的數據。在發送時,應用進程把數據傳輸給內核中的發送緩存,然后就去做其他事情(典型的異步),然后內核在合適的時候把數據發送出去。接收時,內核把收到的數據放入接收緩存,應用進程在合適的時候讀取緩存中的數據。(這兩個緩存非常重要,在之后各種IO模型都會在這兩個緩存上搞事情)
5)面向字節流。“流”是指流入到進程或從進程流出的字節序列。雖然應用進程和TCP的交互式一次一個大小不等的數據塊,但TCP把應用進程傳過來的數據看成一連串的無結構的字節流(看成是連續的)。
tcp面向流的概念圖
TCP並不關心應用進程一次把多長的報文發送到TCP的緩存中,而是根據對方給出的窗口值和當前網絡擁塞的程度來決定一個報文段應包含多少個字節--如果應用進程傳送到TCP緩存的數據塊太長,TCP就划分短一些再傳送;如果應用進程一次只發過來一個字節,TCP也可以累積有足夠多的字節后再構成報文段發送出去。
可靠傳輸的工作原理】
說TCP是可靠的,那什么樣的條件才算可靠的呢?
理想的可靠傳輸條件有兩個特點:
1) 傳輸信道不產生差錯。
2) 不管多快的發送速度,接收方總能來得及處理收到的數據。
我們不可能達到理想條件,但我們可以盡可能達到。
要達到第一點的方法是,當出現差錯的時候,就讓發送方重發出現差錯的數據;
達到第二點的方法是,接收方來不及處理數據時,及時告訴發送方適當降低下發送速度。
第一點的方法怎么實現呢?先介紹簡單的停止、等待協議。
停止、等待協議(做個了解,為后面做鋪墊)]
“停止、等待”就是發送完一個分組(數據單元的統稱,在IP稱作數據表,在TCP層稱作報文段)就停止發送,等待對方的確認。在收到確認后再發送下一個分組。
這種協議會遇到三種情況。
情況1.無差錯情況]
A發送分組M1,發完就暫停發送,等待B確認(ack)。B收到了M1就向A發送確認。以此類推。這種情況不會出現什么問題。
情況2.出現差錯]
如圖上M1分組的情況--M1分組發送給B的時候,B檢測M1出了差錯,就丟棄了M1,然就就什么也不做了(不通知A收到有差錯的分組);或者M1在傳輸過程中丟失了,這時B當然什么都不知道。在這兩種情況下B是不會給A發送任何消息包括確認消息。
遇到這種情況,A采用的辦法叫超時重傳: A只要超過了一段時間仍然沒有收到確認的話,就認為剛才發送的分組丟失了,因而重傳上次發送過的分組。
所以每發完一個分組就為該分組設置一個超時計時器,如果在時間內收到了確認,就撤銷該超時計時器。
這里面有三個要點:
1. A需要暫時保留已發送分組的副本。收到確認后清除副本。
2. 分組和分組的確認進行編號,這樣才能知道哪些分組收到了確認。
3. 從上圖中就可以重傳時間要比平均往返更長一些。(具體長多少,要確定這個值比較麻煩,必須要根據當時的網絡情況具體分析)
情況3. 確認丟失和確認遲到]
這個字面上就很好理解,就是比如B收到了M1分組,但B發送的確認丟失了或者遲到了。 因此A在超時計時器到期后就要重傳M1。這時B又收到之前那個M1了!B應該怎么做?(確認丟失)
1. 丟棄這個重復M1。
2. 然后給A發送M1的確認。這個確認必須發送,不能說之前發送過就不發送了。
這里面有個細節,就是當B再次收到M1時,它是知道這是重復的!
確認遲到--因為網絡擁塞等情況,B發給A的M1確認可能遲到。B的確認遲到,就意味着A等待確認后超時!如果超時后,會再次發送M(B收到這個重復M1后,直接丟棄,如上面確認丟失的做法),如果A按時收到了B相應的確認,那那個遲到確認就重復收到了,A收到這個重復確認怎么辦?很簡單,也是收下后直接丟棄!
像上述停止、等待這類可靠的傳輸協議,我們通常稱為自動重傳請求ARQ(Automatic Repeat reQuest)
缺點:]
停止、等待協議有個特點,從無差錯下面那個圖可以看出來,是線性的!發送完一個數據必須等待確認收到后才發送第二個,可以看成像程序上的同步。 我們可以來算這樣做的信道利用率。TD是A發送數據需要的時間,RTT是數據在信道中的往返時間,TA是B發送確認的時間(發送確認時間非常短)。因為只有TD那個時間才是發送的有用數據,所以利用率公式為:
U = TD/(TD+RTT+TA)
從這個公式就可以看出,當信道特別長(一定特別長,都跨國了),發送功率特別大(科技發展,發送速度必然越來越快)的時候,我們的信道利用率就特別低!也就是說這個信道多數時候是閑置的。
那我們讓A連續發送過個分組,不必每發完一個分組就停下來等待確認呢?類似於我們web開發說的異步服務。
當然有,下面介紹類似這種異步的協議--連續ARQ協議,和再后面的大BOSS滑動窗口協議。
連續ARQ協議]
其實該協議很簡單,就是有一個發送窗口,一個窗口內的5(數字可以改)個分組一起發送出去。然后接收方采用累積確認的方式,即接收方不必對收到的分組逐個發送確認,而是收到幾個分組后,對按序到達的最后一個分組發送確認。
如圖:
(a)圖先發送12345編好號的分組,在收到接收方發送的最后一個分組確認(即第5個分組的確認)后,(b)圖向前移動5個分組,再一次性發送678910分組數據。
根據這個簡單的介紹,連續ARQ協議在這種情況下會出現個大問題:
累積確認有優點也有缺點。優點是:容易實現,即使確認丟失也不必重傳。但缺點是
不能向發送方反映出接收方已經正確收到的所有分組的信息。
例如,如果發送方發送了前5個分組,而中間的第3個分組丟失了。這時接收方只能對前兩個分組發出確認。發送方無法知道后面三個分組的下落,而只好把后面的三個分組都再重傳一次。這就叫做Go-back-N(回退N),表示需要再退回來重傳已發送過的Ⅳ個分組。可見當通信線路質量不好時,連續ARQ協議會帶來負面的影響。
在深入討論TCP的可靠傳輸問題之前,先了解TCP的報文段首部的格式。
上一大段巴拉巴拉,就是說累積確認有缺陷。在解決這個缺陷之前,我們先來看看TCP的首部格式!
TCP報文段首部格式】
TCP傳輸的數據單元是報文段。一個報文段由TCP頭部和報文段數據部分組成。TCP的全部功能都體現在它首部中各個字段的作用。頭部圖如下:
源端口號和目的端口號都好理解。
序號(seq number): 占4字節,范圍是0~2的32次方-1(0~4294967295)。序號增加到4294967295后,下一個序號又回到0。在TCP傳輸的字節流中的中每一個字節都按順序編號。首部中的序號字段值是指本報文段所發送的數據的第一個字節的序號。
例如一段報文的序號字段的值是301,攜帶的數據共100個字節,那下一個報文段的數據序號就是401。(這個序號非常重要,在后面重組報文的時候用)
序號一共就4294967296個,會用完嗎?在一般的情況下,可保證當序號重復使用時,舊的序號數據早已經通過網絡到達終點了。
確認號(ack):是期望收到對方下一個報文段的第一個數據字節的序號。
例如:B正確收到了A發送過來的一個報文段,其序號值是501,數據長度是200字節(序號501~700),這表明B期望收到A的下一個數據號是701,於是B在發送給A的確認報文段中把確認號設置為701。
頭部長度(數據偏移): 頭部長度的單位是32位(4字節),即如果這個字段的值位0110(6),那頭部的長度就是24個字節,固定頭部是20個字節,那選項部分就只有4個字節。 由於頭部字段占4位,即最長的頭部長度為4 * 16 = 60字節,即選項最多40字節。
保留:保留為今后使用,但目前應置為0。
接下來的6個控制位是說明報文段性質用的。
緊急URG:用於處理緊急報文段。也就是這個報文段優先級高,最先處理。要發緊急報文段就把這個位置為1。后面會介紹如何處理緊急報文段。
確認ACK:是經過確認過的報文段。比如建立連接后的所有傳送的報文段都必須把ACK置為1。
推送PSH:推送操作很少使用,可以作為了解。(這個跟我業務上說的push不一樣哈)
復位RST:當RST=1時,表明TCP連接中出現嚴重差錯,必須釋放連接,再重新建立連接。RST置1還用來拒絕一個非法的報文段或拒絕打開一個連接。
同步SYN:在連接建立時用來同步序號。一般跟ACK配合使用。
當SYN=1而ACK=0時,表明這是一個連接請求報文段。若對方同意建立連接,則在響應的報文段中使SYN=1和ACK=1。
因此,SYN置為1就表示這是一個連接請求或連接接受報文。后面的文章會介紹TCP連接的建立和TCP連接的釋放。
FIN: 表示發送端已經達到數據末尾,也就是說雙方的數據傳送完成,沒有數據可以傳送了,發送FIN標志位的TCP數據包后,連接將被斷開。這個標志的數據包也經常被用於進行端口掃描。
窗口:是TCP流量控制的一個手段(還記得我們之前說實現可靠性的第二個條件嗎?控制發送速度!就是通過窗口來控制發送速度的!)。
這的窗口是指發送本報文段己方的接收窗口(還有發送窗口,但這是指接收窗口),占2字節,所以值是的范圍是0~2的16次方-1間的整數。
窗口值告訴對方(重點!是告訴對方):從本報文段的確認號算起,自己目前允許對方發送的數據量(還能容納多少字節數據),這樣對方就可以控制發送速度。有點繞哈,舉例說明:
如果我發送的這個報文段的確認號是701,窗口值是1000,就表明從701號算起(序號必須是>=701),我還能接收1000個字節數據(接收緩存空間)。
窗口值就是對方設置發送窗口的依據。
校驗和:由發送端填充,接收端對TCP報文段執行CRC算法,以檢驗TCP報文段在傳輸過程中是否有損壞。
這的校驗不僅包括頭部,也包括數據部分。是可靠傳輸的重要保障!
緊急指針:指出本報文段中的緊急數據的字節數。它指出了緊急數據的末尾在報文段中的位置(這不是很理解,沒有關系,在后文會有介紹)!緊急指針僅在URG=1時才有意義。
頭部選項:
典型的頭部選項結構如下圖:
選項的第一個kind說明選項的類型。第二個length指定該選項的總長度,該長度包括kind和length所占的兩個字節。第三個info是選項的具體信息。
有的TCP選項只有kind字段。常見的TCP選項有7種:
kind=0:表示結束選項
kind=1:空選項,沒有特殊含義
kind=2:最大報文段長度(MSS)選項。TCP模塊通常將MSS設置為MTU(IP層的最大傳輸單元,最大值1500)-40(20TCP頭部字節+20IP頭部字節)。所以MSS最大值是1500-40=1460字節。MSS的默認值是536字節。
kind=3:窗口擴大選項。防止窗口值不夠用。如果頭部中窗口值是N,窗口擴大因子是M,則,窗口的最大值是2的(N+M)次方 - 1。
窗口擴大選項可以在雙方初始建立TCP連接時進行協商。如果某一端實現了窗口擴大,當他不在需要擴大其窗口時,將該項值設置成0即可。
kind=4:選擇性確認(SACK)選項。我們前面在停止、等待協議說到會出現重復發送分組或者重復發送確認的情況。SACK就是為改善這種情況發明的技術,它使TCP通信端只重新發送丟失的TCP報文段。
kind=5:SACK實際工作選項。該選項的參數告訴發送方端已經接收到並緩存的是不連續的數據塊(有數據丟失),從而讓發送端可以根據此檢查並重新發送丟失的數據塊。
選擇確認我們后面還會介紹。
kind=8:時間戳選項。該選項主要有兩個功能:
1. 用來計算往返時間RTT。發送方在發送報文段時把當前時鍾的時間值放入時間戳值字段,接收方在確認該報文段時,把時間戳字段值復制到時間戳回送回答字段!
2. 處理TCP序號超過2的32次方的情況!稱為防止序號繞回(PAWS)。序號只有32位,當使用高速網絡,TCP連接的數據傳送中很可能,序號很可能被重復使用!那就是加個時間戳不就區別開了!