TCP協議的主要目的是實現主機之間高度可靠的分組交換傳輸協議。本文將描述協議標準和壹些實現方法。由於計算機網絡在現代社會中不可或缺,TCP協議主要是在網絡不可靠的情況下完成通信,對於軍隊可能特別有用,但對於政府和商業部門也同樣適用。TCP是壹種可靠的端到端面向連接的協議。它支持各種網絡應用。TCP不需要底層太多的服務。它假設下層只能提供不可靠的數據報服務,它可以運行在由各種硬件組成的網絡上。下圖是TCP在層次結構中的位置,它的下層是IP協議。TCP可以根據IP協議提供的服務傳輸大小可變的數據,IP協議負責對數據進行分段重組,在各種網絡中傳輸。
TCP上面是應用程序,下面是IP協議。上層接口包括壹系列類似於操作系統中斷的調用。對於上層應用,TCP應該能夠異步傳輸數據。我們假設下層接口是IP協議接口。為了在不可靠的網絡上實現面向連接的可靠數據傳輸,TCP必須解決可靠性和流量控制問題,為上層應用提供多個接口並同時為多個應用提供數據,同時TCP必須解決連接問題,這樣TCP才可以稱為面向連接。最後,TCP還必須能夠解決通信安全問題。
網絡環境包括通過網關(或其他設備)連接的網絡。網絡可以是局域網、城域網或廣域網,但無論它們是什麽,它們都必須基於分組交換。主機上不同的協議有不同的端口號,壹對進程通過這些端口號進行通信。這種通信不包括計算機中的I/O操作,而只包括網絡上的操作。網絡上的計算機被視為數據包傳輸的源節點和目的節點。特別是,應該註意,計算機中的不同進程可以同時通信。此時,它們會通過端口號進行區分,發送給進程A的數據不會被進程B接收到..
為了傳輸數據,進程會調用TCP,將數據和相應的參數傳輸給TCP,於是TCP會將數據傳輸給目的TCP。當然,這是通過將TCP包封裝在IP包中並在網絡上傳輸來實現的。接收端TCP在接收到數據後會與上層應用進行通信,TCP會保證接收到的數據序列的正確性。盡管下層協議可能無法保證正確的順序。這裏需要說明的是,網關收到這個包後,會對包進行拆包,看是否已經到達目的地。如果沒有,應該通過什麽路線到達目的地?決定後,網關將在下壹個網絡中根據協議重新封裝並傳輸TCP數據包,如果需要,將數據包分成幾段後再傳輸。這個落地檢查過程是壹個耗時的過程。從上面我們可以看到TCP傳輸的基本過程,當然具體過程可能要復雜得多。
在實現TCP的主機上,TCP可以看作是壹個模塊,和文件系統區別不大。TCP也可以調用操作系統的壹些功能。TCP不直接與網絡打交道,控制網絡的任務由專門的設備驅動模塊完成。TCP只是調用IP接口,IP提供TCP需要的所有服務。通過下圖我們可以更清楚的看到TCP協議的結構。
如上所述,TCP連接是可靠的,傳輸數據包的順序是有保證的,保證順序是由壹個序列號來保證的。響應數據包還包含壹個序列號,表明接收方已經準備好了帶有該序列號的數據包。TCP傳輸壹個包的時候,同時把包放入重傳隊列,同時啟動計數器。如果它接收到關於該包的確認信息,它從隊列中刪除該包,如果定時器超時,它需要重新發送該包。請註意,TCP返回的確認信息並不能保證最終接收方會收到數據,這個責任是接收方的責任。
每個用來傳輸TCP的通道都有壹個端口標簽,因為這個標簽是由每個TCP終端決定的,所以TCP可能不是唯壹的。為了保證這個值的唯壹性,應該使用網絡地址和端口號的組合來達到唯壹標識的目的。我們稱之為套接字,通過連接兩端的套接字來標識連接。本地套接字可以與不同的外部套接字通信,並且這種通信是全雙工的。
通過向本地端口發送OPEN命令和外部socket參數來建立連接,TCP返回壹個名稱來標記這個連接,如果以後用戶需要用這個名稱來標記這個連接。為了保存這個連接的信息,我們假設有壹個叫做傳輸控制塊(TCB)的東西來保存它。OPEN命令還指定該連接的建立是主動請求還是被動等待請求。接下來,我們將涉及具體的功能。TCP數據段以互聯網數據報的形式傳輸。IP數據包報頭包含不同的信息字段,包括源地址和目的地址。TCP報頭位於internet報頭之後,提供壹些特定於TCP協議的信息。下圖顯示了TCP報頭的格式:
源端口:16位;
目的端口:16位
序列碼:32位。SYN出現時,序列碼其實是初始序列碼(ISN),第壹個數據字節是ISN+1;
確認碼:32位。如果ACK控制位被置位,該值表示要接收的包的序列碼;
數據偏移量:4位數字,表示數據開始的位置;
保留:6位,必須為0;
控制位:6位;
窗口:16位;
校驗位:16位;
優先級指針:16位,指向優先級數據後的字節;
選項:不定長;但長度必須以字節記錄;選項的具體內容結合具體命令查看;
填充:可變長度,填充內容必須為0,這是為了保證數據開頭的頭和偏移量的組合能被32整除;
我們之前說過,有壹個TCB,裏面存儲的變量包括發送方,接收方的套接字,用戶的發送和接收緩沖區指針等等。除此之外,還有壹些與發送和接收序列號相關的變量:
發送序列變量
SND。UNA-發送未確認
SND。NXT-發送下壹個
SND。WND-發送窗口
SND。上行發送優先級指針
SND。wl 1-上次窗口更新的段序列號。
SND。WL2-上次窗口更新的段確認號。
ISS-初始傳輸序列號
接收序列號
RCV。NXT-接收下壹個
RCV。WND-接收下壹個
RCV。上行接收優先級指針
IRS-初始接收序列號
下圖將幫助您理解傳輸序列中變量之間的關系:
當前段變量
賽格。SEQ段序列號
賽格。ACK段確認標記
賽格。鏡頭段長度
賽格。WND段窗口
賽格。上行段緊急指針
賽格。PRC-分段優先級
連接過程由壹系列狀態表示,包括:LISTEN、SYN-SENT、SYN-RECEIVED、ESTABLISHED、FIN-WAIT-1、FIN-WAIT-2、CLOSE-WAIT、closed、LAST-ACK、TIME-WAIT和CLOSED。關閉表示沒有連接,每個狀態的含義如下:
LISTEN-偵聽來自遠程TCP端口的連接請求;
SYN-SENT-發送連接請求後等待匹配的連接請求;
SYN-RECEIVED-接收並發送連接請求後等待連接請求的確認;
ESTABLISHED-代表壹個開放的連接,數據可以傳輸給用戶;
FIN-WAIT-1-等待遠程TCP的連接中斷請求或之前連接中斷請求的確認;
FIN-WAIT-2-等待來自遠程TCP的連接中斷請求;
關閉-等待-等待本地用戶的連接中斷請求;
關閉-等待遠程TCP確認連接中斷;
LAST-ACK-等待最初發送給遠程TCP的連接中斷請求的確認;
TIME-WAIT-等待足夠的時間,確保遠程TCP收到連接中斷請求的確認;
關閉-沒有連接狀態;
TCP連接過程是壹個狀態轉換,由用戶調用提示:打開、發送、接收、關閉、中止、狀態;;傳輸的數據段,特別是那些包括SYN、ACK、RST和FIN的數據段;;還有壹種是超時,上面提到的metropolis中TCP狀態發生變化。
下圖顯示了TCP狀態的轉換,但該圖不包括錯誤情況和錯誤處理。不要把這個數字作為壹般的解釋。
3.3.序列號
請註意,我們在TCP連接中發送的每個字節都有壹個序列號。因為他們是有編號的,妳可以確認他們的收據。序列號的確認是累積的,即如果用戶收到了X的確認信息,就意味著已經收到了X之前(不包括X)的所有數據。每個數據段中的字節是這樣排列的:第壹個字節按此順序排列在包頭之後。我們需要記住,實際的序列空間是有限的。雖然很大,但還是有限的。它的範圍是0到2的32次方減1。我想熟悉編程的人壹定知道,在計算兩段是否連續時,為什麽要用2的32次方作為模。TCP必須執行的序列號比較操作類型包括:
(a)確定壹些已發送但未確認的序列號;
(b)確定已收到所有序列號;
(c)決定應列入下壹段的序號。
要接收發送數據TCP的確認,在處理確認時必須執行以下比較操作:
SND。UNA =最早確認的序列號;
SND。NXT =要發送的下壹個序列號;
賽格。ACK =接收TCP的確認,並接收TCP期望的下壹個序列號;
賽格。SEQ =數據段的第壹個序列號;
賽格。LEN =數據段中包含的字節數;
賽格。SEG賽格。LEN-1 =數據段的最後壹個序列號。
請註意以下關系:
SND。UNA & lt賽格。ACK = & ltSND。NXT
如果數據段的序列號小於或等於確認號的值,則整個數據段被確認。接收數據時,需要進行以下比較操作:
RCV。NXT =預期序列號和接收窗口的最低邊緣;
RCV。NXT+RCV。WND-1 =最後壹個序列號和接收窗口的最高邊緣;
賽格。SEQ =收到的第壹個序列號;
賽格。SEG賽格。LEN-1 =最後收到的序列號;
上述量具有以下關系:
RCV。NXT = & lt賽格。SEQ <RCV。NXT+RCV。WND或rcv.nxt =
測試的第壹部分是檢查數據段的開始部分是否在接收窗口中,第二部分是檢查數據段的結束部分是否也在接收窗口中。通過以上兩項檢查中的任何壹項都意味著它包含了窗口所需的數據。實際情況會更復雜,因為有零窗口和零數據段,所以我們有以下四種情況:
段長
接收窗口
試驗
賽格。SEQ = RCV。NXT
& gt0
RCV。NXT = & lt賽格。SEQ <RCV。NXT+RCV。WND
& gt0
不能接受的
& gt0
& gt0
RCV。NXT = & lt賽格。SEQ <RCV。NXT+RCV。WND或rcv.nxt =
請註意,接收窗口的大小可以為零。當窗口為零時,它只用於接收ACK信息,因此對於壹個TCP來說,它可以在發送數據的同時使用零大小的窗口來接收數據。即使接收窗口的大小為零,TCP也必須處理所有接收信息的RST和URG字段。
我們還通過計數來保護壹些特定的控制信息,這是通過隱式地使用壹些控制標簽來使數據段可靠地重傳(或確認)來實現的。控制信息不在段數據空間中傳輸,因此,我們必須使用隱式指定的序列號進行控制。SYN和FIN是需要保護的控制量,這兩個控制量只在連接打開和關閉時使用。SYN被認為是第壹個實際數據之間的數據,而FIN是最後壹個實際數據之後的數據。線段長度(SEG。LEN)包括數據和序列號空間。如果SYN出現,SEG。SEQ是SYN的序列號。
初始序列號選擇
該協議對重用特定連接沒有限制。壹個連接由壹對套接字定義。新的連接實例被定義為連接的另壹次恢復,這就帶來了問題:如果TCP確定多個數據段是從上壹個連接的另壹次恢復中獲得的呢?這個問題在連接被快速打開和關閉後,或者因為內存原因關閉後又快速建立後,尤為突出。
為了避免混淆,用戶在恢復使用連接時必須避免混淆序列號。我們必須保證序列號的正確性,即使TCP失敗,我們也不知道之前的序列號是什麽。創建新連接時,會生成壹個新的初始序列號(ISN)生成器,用於選擇新的32位ISN。發生器與32位時鐘的低階字節有關,低階字節的刷新頻率約為4微秒,因此ISN的周期時間約為4.55小時。因此,壹個網絡數據包的最大生存時間(MSL)小於4.55小時,所以我們可以認為ISN是唯壹的。每個連接都有壹個發送序列號和壹個接收序列號。初始發送序列號(ISS)由發送TCP選擇,初始接收序列號在連接建立期間生成。
對於要連接或初始化的連接,兩個TCP必須用彼此的初始序列號同步。這是通過交換控制位SYN和初始序列號來完成的。我們把帶SYN的數據段稱為“SYNs”。這裏不再重復獲得同步的過程。每壹方必須發送自己的序列號,並返回對方序列號的確認。
1)A->;我們的序列號是x。
2)A & lt;我們的序列號已經確認。
3)A & lt;- B SYN對方的序列號是y。
4)答->;B ACK確認對方的序列號。
上面的步驟2和3可以合並,然後可以變成三個階段,所以我們可以稱之為三消息握手。這個過程是必要的,因為序列號與全局時鐘無關,TCP也可以有不同的機制來選擇ISN。收到第壹個SYN的接收方無法知道這個數據段是否被延遲,除非它記住了連接上使用的最新序列號(這通常是不可能的),所以它必須向發送方進行確認。
為了確保TCP獲得的確認是由剛剛發送的數據段生成的,而不是由網絡中仍然存在的舊數據段生成的,TCP必須在MSL時間內保持沈默。本文假設MSL=2小時,這是出於工程需要。如果用戶認為可以,他可以改變MSL。請註意,如果TCP重新初始化,內存中的序列號正在使用,則不需要等待,但必須確保使用的序列號大於當前序列號。
如果主機出現故障而沒有保留任何序列號,則它在MSL時間內不應發送任何數據段。這種情況將在下面解釋。TCP的實現可能不遵守這個規則,但會導致舊數據被當作新數據接收,新數據被當作舊數據拒絕。
每當壹個數據段形成並進入輸出隊列時,TCP會在序列空間中給它賦壹個值。TCP中的多拷貝檢測和序列算法都依賴於這個地址空間,在對方發送或接收之前,輸出隊列中存在的數據包不超過2 ^ 32個。所有冗余數據段將被刪除。如果沒有這項規定,多個數據段將被分配相同的序列號,這將造成混亂。數據段中的序列號與數據段中的字節數壹樣多。
壹般情況下,TCP會保留下壹個要發送的序列號和尚未確認的最舊的序列號。沒有確認就不要再用了。這樣會有風險,序列空間非常大也正是為了這個目的。對於壹個2M網絡來說,耗盡序列空間需要4.5小時,因為壹個數據段可能的最大生存時間只有十分之壹秒,這就留下了足夠的空間;在100M網絡上,需要5.4分鐘,有點短,但是還可以。
如果在實現TCP時沒有空間來保存序列號,則可能無法清除冗余數據包。因此,建議這種類型的TCP實現應該在失敗後等待MSL時間,以確保冗余包被刪除。這種情況有時可能發生在保留序列號的TCP實現中。如果當TCP選擇另壹個TCP連接正在使用的序列號時,主機突然出現故障,就會產生問題。這個問題的本質是主機不知道自己故障了多久,也不知道冗余副本是否還在網絡中。
處理這個問題的方法是等待MSL時間。否則,您將面臨另壹方錯誤接收數據的風險。等待時間也稱為“靜默時間”。實現者可以讓用戶選擇是否等待,但是用戶不必等待MSL時間。
3.4.建立聯系
三消息握手用於建立連接。雙方同時發SYN也沒關系,雙方都會發現這個SYN裏沒有確認,所以會知道這個情況。壹般來說,應該發送壹個“復位”段來解決這種情況。三消息握手降低了連接失敗的可能性。下面是壹個例子。在尖括號中,yes是數據段中的內容和標記。別的我就不說了。
第2行,TCP A發送SYN初始化序列號,表示將使用序列號100;第3行,TCP B給出確認,期待序列號為101的A的數據段;在第4行,TCP A給出壹個確認,在第5行,它也給出壹個確認並發送壹些數據。註意,第4行中的序列號與第5行中的序列號相同,因為ACK信息不占用序列號空間中的序列號。同時請求的情況如下圖所示,只是稍微復雜壹點。
使用三消息握手的主要原因是為了防止使用過期的數據段。為此,必須引入新的控制消息RESET。如果接收TCP處理異步狀態,它會在收到重置後返回監聽狀態。如果TCP處理了以下狀態:ESTABLISHED、FIN-WAIT-1、FIN-WAIT-2、CLOSE-WAIT、CLOSING、LAST-ACK、TIME-WAIT,就會放棄連接,通過用戶。我們將在下面詳細解釋後壹種情況。
通過上面的例子,我們可以看到TCP連接是如何從過期數據段的幹擾中恢復的。註意第4行和第5行中的RST(復位信號)。
半開連接和其他異常情況
如果壹方不經過另壹方就關閉連接,或者雙方無法同步,我們稱之為半開連接狀態。當壹方試圖發送數據時,連接將自動重置。但是,這種情況畢竟是不正常的。應該得到相應的處理。如果A處的連接已經關閉,B並不知道。當B要向A發送數據時,會收到復位信號,表示TCP連接錯誤,需要終止當前連接。
假設兩個進程A和B相互通信時,A的TCP失敗,A依靠操作系統支持TCP的存在。通常,在這種情況下,恢復機制會起作用。當TCP恢復時,A可能希望從恢復點開始工作。這樣,A可能會嘗試打開連接,然後在這個它認為仍然打開的連接上傳輸數據。這時A會從本地(也就是A的)TCP得到錯誤消息“連接未打開”。A的TCP將發送包含SYN的數據段。以下示例將展示這壹過程:
在上面的例子中,甲方收到的信息沒有確認任何事情。這時,A發現了不對勁,給RST發來了控制信息。另壹種情況是當A失敗,而B仍然試圖發送數據。下面的例子可以說明這種情況。請註意,在第2行中,A不理解B發送的信息..
在下面的例子中,甲乙雙方是被動連接的,都在等待SYN信息。當過期的數據包發送給乙方時,它使乙方作出響應。但是,收到響應的A發現有問題,發送RST控制信息,B返回被動監聽狀態。
現實中的情況太多了。讓我們列出壹些產生RST控制信息的規則如下:通常,當接收的信息不是期望的信息時,產生RST。如果妳不確定,不要輕易發送RST控制信息。有三種情況:
如果連接不再存在,並且發送的消息不是RST,那麽應該返回RST。如果您想拒絕SYN壹個不存在的連接,可以使用這個方法。如果到達信息具有ACK字段,則返回的RST信息可以從ACK字段獲得序列號。如果沒有這樣的字段,RST序列號被設置為0,ACK字段是序列號和到達數據段長度的和。連接仍處於關閉狀態。
如果連接處於異步狀態(LISTEN,SYN-SENT,SYN-RECEIVED),並且收到的確認是對未發送數據包的確認,或者收到的數據段的安全級別符合不能建立連接的要求,則發送RST。如果SYN沒有確認,接收到的數據段優先級高於要求的優先級,那麽要麽提高本地優先級(事先得到用戶和系統的許可),要麽RST;應該送;如果接收到的數據段的優先級低於要求的優先級,則認為匹配。當然,如果對方發現優先級不對,在下壹個包中提高了優先級,也不算匹配。如果連接已經進入SYN,則接收到的數據段的優先級必須與本地優先級相同,否則將發送RST。如果到達信息具有ACK字段,則返回的RST信息可以從ACK字段獲得序列號。如果沒有這樣的字段,RST序列號被設置為0,ACK字段是序列號和到達數據段長度的和。連接仍然處於與以前相同的狀態。
如果連接處於同步狀態(ESTABLISHED,FIN-WAIT-1,FIN-WAIT-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT),任何序列號超過接收窗口的數據段都會產生以下結果:將發送壹個空的確認數據段,其中包含當前發送的序列號,並且將包含壹個確認以指示希望。如果是因為安全級別、優先級等問題,那麽發送RST信號,然後進入關閉狀態。