传输控制协议

簡介

資料在TCP層稱為流（Stream），資料分組稱為分段（Segment）。作為比較，資料在IP層稱為Datagram，資料分組稱為分片（Fragment）。 UDP 中分組稱為Message。

運作方式

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

資源使用

主機收到一個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時會自動選擇埠以組成獨一無二的四元組（同一個用戶端埠可用於連接不同的伺服器通訊端；同一個伺服器埠可用於接受不同用戶端通訊端的連接）。
對於不能確認的包、接收但還沒讀取的資料，都會占用作業系統的資源。

資料傳輸

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

可靠傳輸

通常在每個TCP報文段中都有一對序號和確認號。TCP報文傳送者稱自己的位元組流的編號為序號，稱接收到對方的位元組流編號為確認號。TCP報文的接收者為了確保可靠性，在接收到一定數量的連續位元組流後才傳送確認。這是對TCP的一種擴充，稱為選擇確認（Selective Acknowledgement）。選擇確認使得TCP接收者可以對亂序到達的資料塊進行確認。每一個位元組傳輸過後，ISN號都會遞增1。
通過使用序號和確認號，TCP層可以把收到的報文段中的位元組按正確的順序交付給應用層。序號是32位元的無符號數，在它增大到2³²-1時，便會迴繞到0。對於ISN的選擇是TCP中關鍵的一個操作，它可以確保強壯性和安全性。
TCP協定使用序號（sequence number）標識每端發出的位元組的順序，從而另一端接收資料時可以重建順序，無懼傳輸時的包的亂序交付或丟包。在傳送第一個包時（SYN包），選擇一個亂數作為序號的初值，以克制TCP序號預測攻擊.
傳送確認包(Acks)，攜帶了接收到的對方發來的位元組流的編號，稱為確認號，以告訴對方已經成功接收的資料流的位元組位置。Ack並不意味著資料已經交付了上層應用程式。
可靠性通過傳送方檢測到遺失的傳輸資料並重傳這些資料。包括超時重傳（Retransmission timeout，RTO）與重複累計確認（duplicate cumulative acknowledgements，DupAcks）。

基於重複累計確認的重傳

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

超時重傳

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

校驗和

TCP的16位元的校驗和（checksum）的計算和檢驗過程如下：傳送者將TCP報文段的頭部和資料部分的和計算出來，再對其求反碼（一的補數），就得到了校驗和，然後將結果裝入報文中傳輸。（這裡用反碼和的原因是這種方法的迴圈進位使校驗和可以在16位元、32位元、64位元等情況下的計算結果再疊加後相同）接收者在收到報文後再按相同的演算法計算一次校驗和。這裡使用的反碼使得接收者不用再將校驗和欄位儲存起來後清零，而可以直接將報文段連同校驗加總。如果計算結果是全部為一，那麼就表示了報文的完整性和正確性。
注意：TCP校驗和也包括了96位的偽頭部，其中有源位址、目的位址、協定以及TCP的長度。這可以避免報文被錯誤地路由。
按現在的標準，TCP的校驗和是一個比較脆弱的校驗。出錯概率高的資料鏈路層需要更高的能力來探測和糾正連接錯誤。TCP如果是在今天設計的，它很可能有一個32位元的CRC校驗來糾錯，而不是使用校驗和。但是通過在第二層使用通常的CRC校驗或更完全一點的校驗可以部分地彌補這種脆弱的校驗。第二層是在TCP層和IP層之下的，比如PPP或乙太網路，它們使用了這些校驗。但是這也並不意味著TCP的16位元校驗和是冗餘的，對於網際網路傳輸的觀察，表明在受CRC校驗保護的各跳之間，軟體和硬體的錯誤通常也會在報文中引入錯誤，而端到端的TCP校驗能夠捕捉到大部分簡單的錯誤。 這就是應用中的端到端原則。

最大分段大小

最大分段大小 (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發現（RFC 1191見RFC 1191）推導出從傳送方到接收方的網路路徑上的最小MTU，以此動態調整MSS以避免網路IP分片。
MSS發布也被稱作「MSS協商」（MSS negotiation）。嚴格講，這並非是協商出來一個統一的MSS值，TCP允許連接兩端使用各自不同的MSS值。 例如，這會發生在參與TCP連接的一台裝置使用非常少的記憶體處理到來的TCP分組。

TCP窗口縮放選項

TCP窗口尺寸域控制封包在2至65,535位元組。RFC 1323定義的TCP窗口縮放選項用於把最大窗口尺寸從65,535位元組擴大至1G位元組。擴大窗口尺寸是TCP最佳化的需要。
窗口縮放選項盡在TCP三次握手時雙端在SYN包中獨立指出這個方向的縮放係數。該值是16位元窗口尺寸的向左位移數，從0 (表示不位移)至14。
某些路由器或分組防火牆會重寫窗口縮放選項，這可能導致不穩定的網路傳輸。

帶外資料

帶外資料（OOB）是指對緊急資料，中斷或放棄排隊中的資料流；接收方應立即處理緊急資料。完成後，TCP通知應用程式恢復流佇列的正常處理。
OOB並不影響網路，「緊急」僅影響遠端端的處理。這一協定很少被實現。

強制資料遞交

正常情況下，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通訊端不能控制或指出這種情形，只能由協定棧控制。

終結通路

連接終止使用了四路握手過程（或稱四次握手，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半開狀態。即一側關閉了連接，不再傳送資料；但另一側沒有關閉連接，仍可以傳送資料。已關閉的一側仍然應接收資料，直至對側也關閉了連接。
也可以通過測三路握手關閉連接。主機A發出FIN，主機B回覆FIN & ACK，然後主機A回覆ACK.
一些主機（如Linux或HP-UX）的TCP棧能實現半雙工關閉序列。這種主機如果主動關閉一個連接但還沒有讀完從這個連接已經收到的資料，該主機傳送RST代替FIN。這使得一個TCP應用程式能確認遠端應用程式已經讀了所有已傳送資料，並等待遠端側發出的FIN。但是遠端的TCP棧不能區分Connection Aborting RST與Data Loss RST，兩種原因都會導致遠端的TCP棧失去所有的收到資料。 
一些應用協定使用TCP open/close handshaking，因為應用協定的TCP open/close handshaking可以發現主動關閉的RST問題。例如：
s = connect(remote);
send(s, data);
close(s);
TCP/IP棧採用上述方法不能保證所有資料到達對側，如果未讀資料已經到達對側。

埠

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

發展過程

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為應用提供服務。