本頁使用了標題或全文手工轉換

傳輸控制協定

維基百科,自由的百科全書
前往: 導覽搜尋

傳輸控制協定英語:Transmission Control Protocol,縮寫為 TCP)是一種連接導向的、可靠的、基於位元組流傳輸層通訊協定,由IETF的RFC 793定義。在簡化的電腦網路OSI模型中,它完成第四層傳輸層所指定的功能,用戶封包協定(UDP)是同一層內另一個重要的傳輸協定。

在網際網路協定族(Internet protocol suite)中,TCP層是位於IP層之上,應用層之下的中間層。不同主機的應用層之間經常需要可靠的、像管道一樣的連線,但是IP層不提供這樣的流機制,而是提供不可靠的包交換。

應用層向TCP層傳送用於網間傳輸的、用8位元位元組表示的資料流,然後TCP把資料流分割成適當長度的報文段(通常受該電腦連線的網路的資料鏈路層的最大傳輸單元(MTU)的限制)。之後TCP把結果包傳給IP層,由它來通過網路將包傳送給接收端實體的TCP層。TCP為了保證不發生丟包,就給每個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。然後接收端實體對已成功收到的包發回一個相應的確認(ACK);如果傳送端實體在合理的往返時延(RTT)內未收到確認,那麼對應的封包就被假設為已遺失將會被進行重傳。TCP用一個校驗和函式來檢驗資料是否有錯誤;在傳送和接收時都要計算校驗和。

簡介[編輯]

資料在TCP層稱為Stream,資料分組稱為分段(Segment)。作為比較,資料在IP層稱為Datagram,資料分組稱為分片(Fragment)。 UDP 中分組稱為Message。

運作方式[編輯]

簡化版的TCP狀態圖。更詳細的版本見: TCP EFSM 圖,包含了ESTABLISHED狀態的內部狀態。

TCP協定的執行可劃分為三個階段:連線建立(connection establishment)、資料傳送(data transfer)和連線終止(connection termination)。作業系統將TCP連線抽象為通訊端表示的本地端點(local end-point),作為編程介面給程式使用。在TCP連線的生命期內,本地端點要經歷一系列的狀態改變。[1]

建立通路[編輯]

TCP用三路握手(或稱三次握手,three-way handshake)過程建立一個連線。在連線建立過程中,很多參數要被初始化,例如序號被初始化以保證按序傳輸和連線的強壯性。

TCP連線的正常建立

一對終端同時初始化一個它們之間的連線是可能的。但通常是由一端開啟一個通訊端socket)然後監聽來自另一方的連線,這就是通常所指的被動開啟(passive open)。伺服器端被被動開啟以後,用戶端就能開始建立主動開啟(active open)。

  1. 用戶端通過向伺服器端傳送一個SYN來建立一個主動開啟,作為三路握手的一部分。用戶端把這段連線的序號設定為亂數A
  2. 伺服器端應當為一個合法的SYN回送一個SYN/ACK。ACK的確認碼應為A+1,SYN/ACK包本身又有一個隨機產生的序號B
  3. 最後,用戶端再傳送一個ACK。當伺服端收到這個ACK的時候,就完成了三路握手,並進入了連線建立狀態。此時包的序號被設定為收到的確認號A+1,而回應號則為B+1

如果伺服器端接到了用戶端發的SYN後回了SYN-ACK後用戶端掉線了,伺服器端沒有收到用戶端回來的ACK,那麼,這個連線處於一個中間狀態,即沒成功,也沒失敗。於是,伺服器端如果在一定時間內沒有收到的TCP會重發SYN-ACK。在Linux下,預設重試次數為5次,重試的間隔時間從1s開始每次都翻倍,5次的重試時間間隔為1s, 2s, 4s, 8s, 16s,總共31s,第5次發出後還要等32s才知道第5次也超時了,所以,總共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 63s,TCP才會斷開這個連線。使用三個TCP參數來調整行為:tcp_synack_retries 減少重試次數;tcp_max_syn_backlog,增大SYN連線數;tcp_abort_on_overflow決定超出能力時的行為

資源使用[編輯]

主機收到一個TCP包時,用兩端的IP位址與埠號來標識這個TCP包屬於哪個session。使用一張表來儲存所有的session,表中的每條稱作Transmission Control Block(TCB),tcb結構的定義包括連線使用的源埠、目的埠、目的ip、序號、應答序號、對方窗口大小、己方窗口大小、tcp狀態、tcp輸入/輸出佇列、應用層輸出佇列、tcp的重傳有關變數等。

伺服器端的連線數量是無限的,只受記憶體的限制。用戶端的連線數量,過去由於在傳送第一個SYN到伺服器之前需要先分配一個隨機空閒的埠,這限制了用戶端IP位址的對外發出連線的數量上限。從Linux 4.2開始,有了socket選項IP_BIND_ADDRESS_NO_PORT,它通知Linux內核不保留usingbind使用埠號為0時內部使用的臨時埠(ephemeral port),在connect時會自動選擇埠以組成獨一無二的四元組(同一個用戶端埠可用於連線不同的伺服器通訊端;同一個伺服器埠可用於接受不同用戶端通訊端的連線)。[2]

對於不能確認的包、接收但還沒讀取的資料,都會占用作業系統的資源。

資料傳輸[編輯]

在TCP的資料傳送狀態,很多重要的機制保證了TCP的可靠性和強壯性。它們包括:使用序號,對收到的TCP報文段進行排序以及檢測重複的資料;使用校驗和檢測報文段的錯誤,即無錯傳輸[3];使用確認和計時器來檢測和糾正丟包或延時;流控制(Flow control);擁塞控制(Congestion control);遺失包的重傳。

可靠傳輸[編輯]

通常在每個TCP報文段中都有一對序號和確認號。TCP報文傳送者稱自己的位元組流的編號為序號,稱接收到對方的位元組流編號為確認號。TCP報文的接收者為了確保可靠性,在接收到一定數量的連續位元組流後才傳送確認。這是對TCP的一種擴充功能,稱為選擇確認(Selective Acknowledgement)。選擇確認使得TCP接收者可以對亂序到達的資料塊進行確認。每一個位元組傳輸過後,ISN號都會遞增1。

通過使用序號和確認號,TCP層可以把收到的報文段中的位元組按正確的順序交付給應用層。序號是32位元的無符號數,在它增大到232-1時,便會迴繞到0。對於ISN的選擇是TCP中關鍵的一個操作,它可以確保強壯性和安全性。

TCP協定使用序號(sequence number)標識每端發出的位元組的順序,從而另一端接收資料時可以重建順序,無懼傳輸時的包的亂序交付英語packet reordering丟包。在傳送第一個包時(SYN包),選擇一個亂數作為序號的初值,以克制TCP序號預測攻擊英語TCP sequence prediction attack.

傳送確認包(Acks),攜帶了接收到的對方發來的位元組流的編號,稱為確認號,以告訴對方已經成功接收的資料流的位元組位置。Ack並不意味著資料已經交付了上層應用程式。

可靠性通過傳送方檢測到遺失的傳輸資料並重傳這些資料。包括超時重傳(Retransmission timeout,RTO)與重複累計確認(duplicate cumulative acknowledgements,DupAcks)。

基於重複累計確認的重傳[編輯]

如果一個包(不妨設它的序號是100,即該包始於第100位元組)遺失,接收方就不能確認這個包及其以後的包,因為採用了累計ack。接收方在收到100以後的包時,發出對包含第99位元組的包的確認。這種重複確認是包遺失的訊號。傳送方如果收到3次對同一個包的確認,就重傳最後一個未被確認的包。閾值設為3被證實可以減少亂序包導致的無作用的重傳(spurious retransmission)現象。[4] 選擇性確認英語selective acknowledgment(SACK)的使用能明確反饋哪個包收到了,極大改善了TCP重傳必要的包的能力。

超時重傳[編輯]

傳送方使用一個保守估計的時間作為收到封包的確認的超時上限。如果超過這個上限仍未收到確認包,傳送方將重傳這個封包。每當傳送方收到確認包後,會重設這個重傳定時器。典型地,定時器的值設定為 其中是時鐘粒度。[5] 進一步,如果重傳定時器被觸發,仍然沒有收到確認包,定時器的值將被設為前次值的二倍(直到特定閾值)。這可對抗 中間人攻擊方式的拒絕服務攻擊,這種攻擊愚弄傳送者重傳很多次導致接受者被壓垮。


資料傳輸舉例[編輯]

TCP資料傳輸
  1. 傳送方首先傳送第一個包含序列號為1(可變化)和1460位元組資料的TCP報文段給接收方。接收方以一個沒有資料的TCP報文段來回覆(只含報頭),用確認號1461來表示已完全收到並請求下一個報文段。
  2. 傳送方然後傳送第二個包含序列號為1461,長度為1460位元組的資料的TCP報文段給接收方。正常情況下,接收方以一個沒有資料的TCP報文段來回覆,用確認號2921(1461+1460)來表示已完全收到並請求下一個報文段。傳送接收這樣繼續下去。
  3. 然而當這些封包都是相連的情況下,接收方沒有必要每一次都回應。比如,他收到第1到5條TCP報文段,只需回應第五條就行了。在例子中第3條TCP報文段被遺失了,所以儘管他收到了第4和5條,然而他只能回應第2條。
  4. 傳送方在傳送了第三條以後,沒能收到回應,因此當時鐘(timer)過時(expire)時,他重發第三條。(每次傳送者傳送一條TCP報文段後,都會再次啟動一次時鐘:RTT)。
  5. 這次第三條被成功接收,接收方可以直接確認第5條,因為4,5兩條已收到。

校驗和[編輯]

TCP的16位元的校驗和(checksum)的計算和檢驗過程如下:傳送者將TCP報文段的頭部和資料部分的和計算出來,再對其求反碼一的補數),就得到了校驗和,然後將結果裝入報文中傳輸。(這裡用反碼和的原因是這種方法的迴圈進位使校驗和可以在16位元、32位元、64位元等情況下的計算結果再疊加後相同)接收者在收到報文後再按相同的演算法計算一次校驗和。這裡使用的反碼使得接收者不用再將校驗和欄位儲存起來後清零,而可以直接將報文段連同校驗加總。如果計算結果是全部為一,那麼就表示了報文的完整性和正確性。

注意:TCP校驗和也包括了96位的偽頭部,其中有源位址、目的位址、協定以及TCP的長度。這可以避免報文被錯誤地路由。

按現在的標準,TCP的校驗和是一個比較脆弱的校驗。出錯機率高的資料鏈路層需要更高的能力來探測和糾正連線錯誤。TCP如果是在今天設計的,它很可能有一個32位元的CRC校驗來糾錯,而不是使用校驗和。但是通過在第二層使用通常的CRC校驗或更完全一點的校驗可以部分地彌補這種脆弱的校驗。第二層是在TCP層和IP層之下的,比如PPP乙太網,它們使用了這些校驗。但是這也並不意味著TCP的16位元校驗和是冗餘的,對於網際網路傳輸的觀察,表明在受CRC校驗保護的各跳之間,軟體和硬體的錯誤通常也會在報文中引入錯誤,而端到端的TCP校驗能夠捕捉到大部分簡單的錯誤。[6] 這就是應用中的端到端原則。

流量控制[編輯]

流量控制英語flow control (data)用來避免主機分組傳送得過快而使接收方來不及完全收下,一般由接收方通告給傳送方進行調控。

TCP使用滑動窗口協定英語Sliding Window Protocol實現流量控制。接收方在「接收窗口」域指出還可接收的位元組數量。傳送方在沒有新的確認包的情況下至多傳送「接收窗口」允許的位元組數量。接收方可修改「接收窗口」的值。

TCP包的序號與接收窗口的行為很像時鐘。

當接收方宣布接收窗口的值為0,傳送方停止進一步傳送資料,開始了「保持定時器」(persist timer),以避免因隨後的修改接收窗口的封包遺失使連線的雙側進入死結,傳送方無法發出資料直至收到接收方修改窗口的指示。當「保持定時器」到期時,TCP傳送方嘗試恢復傳送一個小的ZWP包(Zero Window Probe),期待接收方回覆一個帶著新的接收窗口大小的確認包。一般ZWP包會設定成3次,如果3次過後還是0的話,有的TCP實現就會發RST把連結斷了。

如果接收方以很小的增量來處理到來的資料,它會發布一系列小的接收窗口。這被稱作愚蠢窗口綜合症,因為它在TCP的封包中傳送很少的一些位元組,相對於TCP包頭是很大的開銷。解決這個問題,就要避免對小的window size做出回應,直到有足夠大的window size再回應:

  • 接收端使用David D Clark演算法:如果收到的資料導致window size小於某個值,可以直接ack把window給關閉了,阻止了傳送端再發資料。等到接收端處理了一些資料後windows size大於等於了MSS,或者接收端buffer有一半為空,就可以把window開啟讓傳送端再發資料過來。
  • 傳送端使用著名的Nagle演算法來延時處理,條件一:Window Size>=MSS 或是 Data Size >=MSS;條件二:等待時間或是超時200ms,這兩個條件有一個滿足,才會發資料,否則就是在積累資料。Nagle演算法預設是開啟的,所以對於一些需要小包場景的程式——比如像telnet或ssh這樣的互動性程式,需要關閉這個演算法。可以在Socket設定TCP_NODELAY選項來關閉這個演算法。

擁塞控制[編輯]

擁塞控制是傳送方根據網路的承載情況控制分組的傳送量,以取得高效能又能避免擁塞崩潰(congestion collapse,網路效能下降幾個數量級)。這在網路流之間產生近似最大最小公平英語max-min fairness分配。

傳送方與接收方根據確認包或者包遺失的情況,以及定時器,估計網路擁塞情況,從而修改資料流的行為,這稱為擁塞控制或網路擁塞避免。

TCP的現代實現包含四種相互影響的擁塞控制演算法: 慢開始, 擁塞避免英語TCP congestion avoidance algorithm, 快重傳英語fast retransmit, 快恢復英語fast recovery (RFC 5681).

此外,傳送方採取「超時重傳」(retransmission timeout,RTO),這是估計出來回通訊延遲 (RTT) 以及RTT的方差。

RFC793中定義的計算SRTT的經典演算法:指數加權移動平均(Exponential weighted moving average)

  1. 先採樣RTT,記下最近好幾次的RTT值。
  2. 做平滑計算SRTT公式為:SRTT =( α * SRTT ) + ((1- α) * RTT),其中 α 取值在0.8 到 0.9之間
  3. 計算RTO,公式:RTO = min [ UBOUND, max [ LBOUND, (β * SRTT) ] ]其中 UBOUND是最大的timeout時間上限值,LBOUND是最小的timeout時間下限值,β值一般在1.3到2.0之間。

1987年,計算RTT的Karn演算法英語Karn's Algorithm或TCP時間戳(RFC 1323),最大特點是——忽略重傳,不把重傳的RTT做採樣。但是,如果在某一時間,網路閃動,突然變慢了,產生了比較大的延時,這個延時導致要重轉所有的包(因為之前的RTO很小),於是,因為重轉的不算,所以,RTO就不會被更新,這是一個災難。為此,Karn演算法一發生重傳,就對現有的RTO值翻倍。這就是的Exponential backoff。

1988年,在RFC 6298中給出范·雅各布森演算法取平均以獲得平滑往返時延(Smoothed Round Trip Time,SRTT),作為最終的RTT估計值。這個演算法在被用在今天的TCP協定中:

SRTT= SRTT+ α(RTT– SRTT)DevRTT= (1-β)*DevRTT+ β*(|RTT-SRTT|)RTO= µ *SRTT + ∂ *DevRTT

其中:DevRTT是Deviation RTT。在Linux下,α = 0.125,β = 0.25, μ = 1,∂= 4

目前有很多TCP擁塞控制演算法英語TCP congestion control在研究中。

最大分段大小[編輯]

最大分段大小 (MSS)是在單個分段中TCP願意接受的資料的位元組數最大值。MSS應當足夠小以避免IP分片,它會導致丟包或過多的重傳。在TCP連線建立時,雙端在SYN報文中用MSS選項宣布各自的MSS,這是從雙端各自直接相連的資料鏈路層最大傳輸單元(MTU)的尺寸減去固定的IP首部和TCP首部長度。乙太網MTU為1500位元組, MSS值可達1460位元組。使用IEEE 802.3的MTU為1492位元組,MSS可達1452位元組。如果目的IP位址為「非原生的」,MSS通常的預設值為536(這個預設值允許20位元組的IP首部和20位元組的TCP首部以適合576位元組IP資料報)。此外,傳送方可用傳輸路徑MTU發現英語path MTU discovery(見RFC 1191)推匯出從傳送方到接收方的網路路徑上的最小MTU,以此動態調整MSS以避免網路IP分片

MSS發布也被稱作「MSS協商」(MSS negotiation)。嚴格講,這並非是協商出來一個統一的MSS值,TCP允許連線兩端使用各自不同的MSS值。[7] 例如,這會發生在參與TCP連線的一台裝置使用非常少的記憶體處理到來的TCP分組。

選擇確認[編輯]

最初採取累計確認的TCP協定在丟包時效率很低。例如,假設通過10個分組發出了1萬個位元組的資料。如果第一個分組遺失,在純粹的累計確認協定下,接收方不能說它成功收到了1,000到9,999位元組,但未收到包含0到999位元組的第一個分組。因而,傳送方可能必須重傳所有1萬個位元組。

為此,TCP採取了「選擇確認」(selective acknowledgment,SACK)選項。RFC 2018對此定義為允許接收方確認它成功收到的分組的不連續的塊,以及基礎TCP確認的成功收到最後連續位元組序號。這種確認可以指出SACK block,包含了已經成功收到的連續範圍的開始與結束位元組序號。在上述例子中,接收方可以發出SACK指出序號1000到9999,傳送方因此知道只需重發第一個分組(位元組 0 到 999)。

TCP傳送方會把亂序收包當作丟包,因此會重傳亂序收到的包,導致連線的效能下降。重複SACK選項(duplicate-SACK option)是定義在RFC 2883中的SACK的一項擴充功能,可解決這一問題。接收方發出D-ACK指出沒有丟包,接收方恢復到高傳輸率。D-SACK使用了SACK的第一個段來做標誌,

  • 如果SACK的第一個段的範圍被ACK所覆蓋,那麼就是D-SACK;
  • 如果SACK的第一個段的範圍被SACK的第二個段覆蓋,那麼就是D-SACK

D-SACK旨在告訴傳送端:收到了重複的資料,封包沒有丟,丟的是ACK包;或者「Fast Retransmit演算法」觸發的重傳不是因為發出去的包丟了,也不是因為回應的ACK包丟了,而是因為網路延時導致的reordering。

SACK選項並不是強制的。僅當雙端都支援時才會被使用。TCP連線建立時會在TCP頭中協商SACK細節。在 Linux下,可以通過tcp_sack參數開啟SACK功能(Linux 2.4後預設開啟)。Linux下的tcp_dsack參數用於開啟D-SACK功能(Linux 2.4後預設開啟)。選擇確認也用於流控制傳輸協定 (SCTP).

TCP窗口縮放選項[編輯]

TCP窗口尺寸域控制封包在2至65,535位元組。RFC 1323定義的TCP窗口縮放選項英語TCP window scale option用於把最大窗口尺寸從65,535位元組擴大至1G位元組。擴大窗口尺寸是TCP最佳化英語TCP tuning的需要。

窗口縮放選項盡在TCP三次握手時雙端在SYN包中獨立指出這個方向的縮放係數。該值是16位元窗口尺寸的向左位移數,從0 (表示不位移)至14。

某些路由器或分組防火牆會重寫窗口縮放選項,這可能導致不穩定的網路傳輸。[8]

TCP時間戳[編輯]

RFC 1323定義了TCP時間戳,並不對應於系統時鐘,使用隨機值初始化。許多作業系統每毫秒增加一次時間戳;但RFC只規定tick應當成比例。

有兩個時間戳域:

4位元組的傳送時間戳值
4位元組的回應回覆時間戳值(最近收到資料的時間戳)

TCP時間戳用於「防止序列號迴繞演算法」(Protection Against Wrapped Sequence numbers,PAWS),細節見RFC 1323。PAWS用於接收窗口跨序號迴繞邊界。這種情形下一個包可能會重傳以回答問題:「是否是第一個還是第二個4 GB的序號?」時間戳可以打破這一問題。

另外,Eifel檢測演算法(RFC 3522)使用TCP時間戳確定如果重傳發生是因為丟包還是簡單亂序。

最近統計表明時間戳的採用率停滯在~40%,這歸因於Windows伺服器從Windows Server 2008起降低了支援。[9].

帶外資料[編輯]

帶外資料英語out-of-band data(OOB)是指對緊急資料,中斷或放棄排隊中的資料流;接收方應立即處理緊急資料。完成後,TCP通知應用程式恢複流佇列的正常處理。

OOB並不影響網路,「緊急」僅影響遠端端的處理。這一協定很少被實現。[10][11]

強制資料遞交Forcing data delivery[編輯]

正常情況下,TCP等待200 ms以準備一個完整分組發出(納格演算法試圖把小的資訊組裝為單一的包)。者產生了小的、但潛在很嚴重的延遲並在傳遞一個檔案時不斷重複延遲。例如,典型傳送塊是4 KB,典型的MSS是1460位元組,在10 Mbit/s乙太網上發出兩個包,每個耗時約~1.2 ms,隨後是剩餘1176個位元組的包,之後是197 ms停頓因為TCP等待裝滿緩衝區。

對於telnet,每次用戶擊鍵的回應,如果有200 ms將會非常煩人。

socket選項TCP_NODELAY能放棄預設的200 ms傳送延遲。應用程式使用這個socket選項強制發出資料。

RFC定義了PSH能立即發出位元。Berkeley通訊端不能控制或指出這種情形,只能由協定棧控制.[12]

終結通路[編輯]

TCP連線的正常終止
連線終止

連線終止使用了四路握手過程(或稱四次握手,four-way handshake),在這個過程中連線的每一側都獨立地被終止。當一個端點要停止它這一側的連線,就向對側傳送FIN,對側回覆ACK表示確認。因此,拆掉一側的連線過程需要一對FIN和ACK,分別由兩側端點發出。

首先發出FIN的一側,如果給對側的FIN回應了ACK,那麼就會超時等待2*MSL時間,然後關閉連線。在這段超時等待時間內,原生的埠不能被新連線使用;避免延時的包的到達與隨後的新連線相混淆。RFC793定義了MSL為2分鐘,Linux設定成了30s。參數tcp_max_tw_buckets控制並行的TIME_WAIT的數量,預設值是180000,如果超限,那麼,系統會把多的TIME_WAIT狀態的連線給destory掉,然後在記錄檔里打一個警告(如:time wait bucket table overflow)

連線可以工作在TCP半開英語TCP half-open狀態。即一側關閉了連線,不再傳送資料;但另一側沒有關閉連線,仍可以傳送資料。已關閉的一側仍然應接收資料,直至對側也關閉了連線。

也可以通過測三次握手關閉連線。主機A發出FIN,主機B回覆FIN & ACK,然後主機A回覆ACK.[13]

一些主機(如LinuxHP-UX)的TCP棧能實現半雙工關閉序列。這種主機如果主動關閉一個連線但還沒有讀完從這個連線已經收到的資料,該主機傳送RST代替FIN[14]。這使得一個TCP應用程式能確認遠端應用程式已經讀了所有已傳送資料,並等待遠端側發出的FIN。但是遠端的TCP棧不能區分Connection Aborting RSTData Loss RST,兩種原因都會導致遠端的TCP棧失去所有的收到資料。

一些應用協定使用TCP open/close handshaking,因為應用協定的TCP open/close handshaking可以發現主動關閉的RST問題。例如:

s = connect(remote);
send(s, data);
close(s);

TCP/IP棧採用上述方法不能保證所有資料到達對側,如果未讀資料已經到達對側。

狀態編碼[編輯]

下表為TCP狀態碼列表,以S指代伺服器,C指代用戶端,S&C表示兩者,S/C表示兩者之一:[15]

LISTEN S
伺服器等待從任意遠端TCP埠的連線請求。偵聽狀態。
SYN-SENT C
客戶在傳送連線請求後等待符合的連線請求。通過connect()函式向伺服器發出一個同步(SYNC)訊號後進入此狀態。
SYN-RECEIVED S
伺服器已經收到並行送同步(SYNC)訊號之後等待確認(ACK)請求。
ESTABLISHED S&C
伺服器與客戶的連線已經開啟,收到的資料可以傳送給用戶。資料傳輸步驟的正常情況。此時連線兩端是平等的。這稱作全連線。
FIN-WAIT-1 S&C
(伺服器或客戶)主動關閉端呼叫close()函式發出FIN請求包,表示本方的資料傳送全部結束,等待TCP連線另一端的ACK確認包或FIN&ACK請求包。
FIN-WAIT-2 S&C
主動關閉端在FIN-WAIT-1狀態下收到ACK確認包,進入等待遠端TCP的連線終止請求的半關閉狀態。這時可以接收資料,但不再傳送資料。
CLOSE-WAIT S&C
被動關閉端接到FIN後,就發出ACK以回應FIN請求,並進入等待本地用戶的連線終止請求的半關閉狀態。這時可以傳送資料,但不再接收資料。
CLOSING S&C
在發出FIN後,又收到對方發來的FIN後,進入等待對方對己方的連線終止(FIN)的確認(ACK)的狀態。少見。
LAST-ACK S&C
被動關閉端全部資料傳送完成之後,向主動關閉端傳送FIN,進入等待確認包的狀態。
TIME-WAIT S/C
主動關閉端接收到FIN後,就傳送ACK包,等待足夠時間以確保被動關閉端收到了終止請求的確認包。【按照RFC 793,一個連線可以在TIME-WAIT保證最大四分鐘,即最大分段壽命(maximum segment lifetime)的2倍】
CLOSED S&C
完全沒有連線。

[編輯]

TCP使用了埠號Port number)的概念來標識傳送方和接收方的應用層。對每個TCP連線的一端都有一個相關的16位元的無符號埠號分配給它們。埠被分為三類:眾所周知的、註冊的和動態/私有的。眾所周知的埠號是由網際網路賦號管理局(IANA)來分配的,並且通常被用於系統一級或根行程。眾所周知的應用程式作為伺服器程式來執行,並被動地偵聽經常使用這些埠的連線。例如:FTPTELNETSMTPHTTP等。註冊的埠號通常被用來作為終端用戶連線伺服器時短暫地使用的源埠號,但它們也可以用來標識已被第三方註冊了的、被命名的服務。動態/私有的埠號在任何特定的TCP連線外不具有任何意義。可能的、被正式承認的埠號有65535個。

封包結構[編輯]

偏移 位0–3 4–7 8–15 16–31
0 來源連接埠 目的連接埠
32 序列號碼
64 確認號碼
96 報頭長度 保留 標誌符 窗口大小
128 校驗和 緊急指標
160 選項欄位
160/192+  
資料
 
  • 來源連接埠(16位元長)-辨識傳送連接埠
  • 目的連接埠(16位元長)-辨識接收連接埠
  • 序列號(seq,32位元長)
    • 如果含有同步化旗標(SYN),則此為最初的序列號;第一個資料位元的序列碼為本序列號加一。
    • 如果沒有同步化旗標(SYN),則此為第一個資料位元的序列碼。
  • 確認號(ack,32位元長)—期望收到的資料的開始序列號。也即已經收到的資料的位元組長度加1。
  • 報頭長度(4位元長)—以4位元組為單位計算出的資料段開始位址的偏移值。
  • 保留—須置0
  • 標誌符
    • URG—為1表示高優先級封包,緊急指標欄位有效。
    • ACK—為1表示確認號欄位有效
    • PSH—為1表示是帶有PUSH標誌的資料,指示接收方應該儘快將這個報文段交給應用層而不用等待緩衝區裝滿。
    • RST—為1表示出現嚴重差錯。可能需要重現建立TCP連線。還可以用於拒絕非法的報文段和拒絕連線請求。
    • SYN—為1表示這是連線請求或是連線接受請求,用於建立連線和使順序號同步
    • FIN—為1表示傳送方沒有資料要傳輸了,要求釋放連線。
  • 窗口(WIN,16位元長)—表示從確認號開始,本報文的接受方可以接收的位元組數,即接收窗口大小。用於流量控制。
  • 校驗和(Checksum,16位元長)—對整個的TCP報文段,包括TCP頭部和TCP資料,以16位元字進行計算所得。這是一個強制性的欄位。
  • 緊急指標(16位元長)—本報文段中的緊急資料的最後一個位元組的序號。
  • 選項欄位—最多40位元組。每個選項的開始是1位元組的kind欄位,說明選項的類型。
    • 0:選項表結束(1位元組)
    • 1:無操作(1位元組)用於選項欄位之間的字邊界對齊。
    • 2:最大報文段長度(4位元組,Maximum Segment Size,MSS)通常在建立連線而設定SYN標誌的封包中指明這個選項,指明本端所能接收的最大長度的報文段。通常將MSS設定為(MTU-40)位元組,攜帶TCP報文段的IP資料報的長度就不會超過MTU,從而避免本機發生IP分片。只能出現在同步報文段中,否則將被忽略。
    • 3:窗口擴大因子(4位元組,wscale),取值0-14。用來把TCP的窗口的值左移的位數,使窗口值乘倍。只能出現在同步報文段中,否則將被忽略。這是因為現在的TCP接收資料緩衝區(接收窗口)的長度通常大於65535位元組。
    • 4:sackOK—傳送端支援並同意使用SACK選項。
    • 5:SACK實際工作的選項。
    • 8:時間戳(10位元組,TCP Timestamps Option,TSopt)
      • 傳送端的時間戳(Timestamp Value field,TSval,4位元組)
      • 時間戳回顯應答(Timestamp Echo Reply field,TSecr,4位元組)

發展過程[編輯]

TCP是一個複雜的但同時又是在發展之中的協定。儘管許多重要的改進被提出和實施,發表於1981年的RFC793中說明的TCP(TCP-Tahoe)的許多基本操作還是未作多大改動。RFC1122:《網際網路對主機的要求》闡明了許多TCP協定的實現要求。RFC2581:《TCP的擁塞控制》是一篇近年來關於TCP的很重要的RFC,描述了更新後的避免過度擁塞的演算法。寫於2001年的RFC3168描述了對明顯擁塞的報告,這是一種擁塞避免的號誌機制。在21世紀早期,在所有網際網路的封包中,通常有大約95%的包使用了TCP協定。常見的使用TCP的應用層有HTTP/HTTPS(全球資訊網協定),SMTP/POP3/IMAP(電子郵件協定)以及FTP(檔案傳輸協定)。這些協定在今天被廣泛地使用,這證明了它們的原作者的創造是卓越的。

最近,一個新協定已經被加州理工學院的科研人員開發出來,命名為FAST TCP(基於快速活動佇列管理的規模可變的傳輸控制協定)。它使用排隊延遲作為擁塞控制訊號;但是因為端到端的延遲通常不僅僅包括排隊延遲,所以FAST TCP(或更一般地,所有基於排隊延遲的演算法)在實際網際網路中的能否工作仍然是一個沒有解決的問題。

應用[編輯]

TCP並不是對所有的應用都適合,一些新的帶有一些內在的脆弱性的運輸層協定也被設計出來。比如,實時應用並不需要甚至無法忍受TCP的可靠傳輸機制。在這種類型的應用中,通常允許一些丟包、出錯或擁塞,而不是去校正它們。例如通常不使用TCP的應用有:實時流多媒體(如網際網路廣播)、實時多媒體播放器和遊戲、IP電話(VoIP)等等。任何不是很需要可靠性或者是想將功能減到最少的應用可以避免使用TCP。在很多情況下,當只需要多路復用應用服務時,用戶資料報協定(UDP)可以代替TCP為應用提供服務。

參考資料[編輯]

  • Timothy S. Ramteke: Networks, Second Edition., Prentice-Hall 2001, ISBN 0-13-901265-6
  • Torsten Braun , Martina Zitterbart: Hochleistungskommunikation, Bd.2, Transportdienste und Transportprotokolle , Oldenbourg 1996, ISBN 978-3-486-23088-8

參見[編輯]

外部連結[編輯]