Transmission Control Protocol

概要

TCPはインターネット・プロトコル・スイートの初期からある2つのコンポーネントの1つで、もう1つは Internet Protocol (IP) である。そのため、スイート全体を一般に「TCP/IP」と呼ぶ。
TCPは、送信元のコンピュータ上のプログラムから別のコンピュータ上の別のプログラムへと信頼できる順序通りのオクテット列の転送を行う。
World Wide Web、電子メール、リモート管理、File Transfer Protocol (FTP) などの主要なインターネット・アプリケーションはTCPを利用している。
高信頼のデータストリーム・サービスを必要としないアプリケーションでは User Datagram Protocol (UDP) を使うこともある。
UDPは信頼性よりもレイテンシ低減を重視したデータグラムサービスを提供する。
OSI参照モデルのトランスポート層にあたる。
ネットワーク層のプロトコルであるIPの上位プロトコルとして使われる。
IPヘッダでのプロトコル番号は6である。
TCPは、セッションという形で1対1の通信を実現し、パケットシーケンスチェックによる欠損パケット再送などのエラー訂正機能などを持ち、データ転送などの信頼性の必要な場面でよく使用される。
一方他のトランスポート層プロトコルに比べ、プロトコル上のオーバヘッドが大きい為、比較的低速となる。
IETFが、RFC 793 (STD 7) に技術仕様を規定している。
上位プロトコルとして、HTTP、FTP、Telnet、SSHなどがある。

起源

1974年5月、Institute of Electrical and Electronic Engineers (IEEE) が "A Protocol for Packet Network Interconnection" と題した論文を出版。著者はヴィントン・サーフとロバート・カーンで、ノード間でパケット通信を使い資源を共有するインターネットワーキングのプロトコルを記述したものである。このモデルでの中核制御コンポーネントが Transmission Control Program で、ホスト間のコネクション指向のリンクとデータグラムサービスの両方を含んでいた。当初一体だった Transmission Control Program は後にモジュール化されたアーキテクチャに分割され、コネクション指向部分の Transmission Control Protocol とデータグラムサービス部分の Internet Protocol に分けられた。このモデルを一般に TCP/IP と呼ぶが、公式にはインターネット・プロトコル・スイートと呼ぶようになった。

ネットワーク機能

TCPは、アプリケーションプログラムと Internet Protocol (IP) の中間の層で通信サービスを提供する。すなわち、アプリケーションプログラムがIPを使って大きなデータの塊を送信したいという場合、直接そのデータをIPのサイズで分割して一連のIP要求を発行するのではなく、TCPに1度要求を発行するだけで、TCPにIPの詳細を任せることができる。
IPはパケットと呼ばれる情報の断片をやり取りする形で機能する。パケットは、ヘッダ部に本体が続く形で構成されるオクテット列である。ヘッダ部には、そのパケットの宛先があり、その宛先に到達するために中継で使用すべきルーターを指定することもある。本体にはIPが転送すべきデータが格納される。
ネットワークが混雑（輻輳）したり、トラフィックを負荷分散させようとしたり、その他ネットワークの予測できない振る舞いにより、IPパケットは喪失したり、重複したり、順序がばらばらで届いたりする。TCPはそれらの問題を検出し、喪失データの再送を要求し、データの順序を正しく並べ替え、さらにネットワークの混雑が起きにくくなるよう制御して他の問題が発生する可能性を低くする。TCPの受信側は、オクテット列の順序を元通りに再現すると、それをアプリケーションプログラムに渡す。したがってTCPは、アプリケーションに対してネットワークの詳細を隠蔽して抽象化しているといえる。
TCPはインターネットの様々な主要アプリケーションで広く使われている。例えば、World Wide Web (WWW)、電子メール、File Transfer Protocol、Secure Shell、ファイル共有、一部のストリーミングなどがある。
TCPは高速さよりも正確さに最適化されており、そのためメッセージの順序がばらばらだったり、喪失したメッセージの再送を待ったりすることがあると、秒のオーダーの比較的長い遅延が生じることがある。これはリアルタイム性を求められるVoIPなどのアプリケーションには向いていない。そのような用途には一般に User Datagram Protocol (UDP) 上の Real-time Transport Protocol (RTP) などのプロトコルが推奨される。
TCPは高信頼ストリーム配送サービスであり、重複したり喪失したりすることなく、あるホストから別のホストにデータを配送することを保証する。パケット転送は信頼できないので、確認応答と再送という技法でパケット転送の信頼性を保証している。この基本的技法では、受信側がデータを受信するたびに確認応答メッセージを送り返す必要がある。送信側は送信した各パケットの記録を保持しておき、次のパケットを送信する前に確認応答を待つ。送信側はまたパケット送信時からのタイマーを保持しており、規定時間以内に確認応答がなければ再送を行う。これは、パケットが喪失した場合や内容が壊れていて確認応答もできない場合に必要とされる。
TCPには一連の規則がある。Internet Protocol と組合わせて使う際の規則、インターネット上のホスト間で「メッセージ単位の形式で」データを送信するためのIPの規則である。IPがデータの実際の配送を扱う一方、TCPは「セグメント (segment)」と呼ばれるデータ単位の転送を扱う。セグメントはネットワーク内での効率的ルーティングのためにメッセージを分割したものである。例えばWebサーバがHTMLファイルを送信する場合、そのサーバのTCP層（トランスポート層）でそのファイルのオクテット列を一連のセグメントに分割し、セグメント毎にIP層（ネットワーク層）に渡す。IP層はTCPセグメントに宛先IPアドレスなどを含むIPヘッダを付与して、IPパケットにカプセル化する。各パケットは同じ宛先アドレスを付与されているが、ネットワーク内の転送経路はパケット毎に異なる可能性がある。宛先のコンピュータ上のクライアントプログラムがそれらを受信すると、TCP層はセグメント群に誤りがないことを確認し、それらを正しい順序で再結合し、アプリケーションに渡す。

リソースの使い方

多くの実装では、テーブルの1エントリを動作中のOSプロセスとのセッションにマッピングする。TCPセグメントにはセッション識別子がないため、通信している双方でクライアントのアドレスとポートでセッションを識別する。パケットを受信すると、TCPソフトウェアはそのテーブルを参照して、対応するプロセスを見つける。
サーバ側でのセッション数はメモリ容量にのみ制限され、コネクション確立要求がくるたびに増えていく。しかし、クライアントはサーバに最初のSYNセグメントを送る前に無作為にポートを選んで確保しなければならない。このポートはコネクションをクローズするまで確保され続け、実質的にクライアントの持つIPアドレス毎の外に出て行くコネクション数を制限している。アプリケーションが不要になったコネクションをクローズしそこねると、空いているポートが足りなくなり、新たなTCPコネクションを確立できなくなる。
また、通信する双方で確認応答を受け取っていない送信済みデータとアプリケーションに渡す前の受信データを格納しておく領域を確保する必要がある。

高信頼転送

TCPは「シーケンス番号」を使ってデータの各バイトを識別する。シーケンス番号は双方のホストが送信するバイト列に先頭から振られる番号であり、それによってデータがどう分割されても、順番が入れ替わっても、転送中に失われても、元のデータを復元できる。ペイロードの各バイトを送るたびにシーケンス番号をインクリメントしなければならない。3ウェイ・ハンドシェイクの最初の2ステップで、双方のホストは初期シーケンス番号 (ISN) をやりとりする。この番号は任意であり、TCPシーケンス番号予測攻撃への防御のために予測不可能な値とすべきである。
TCPは「累積確認応答」方式を採用しており、受信側が確認応答を返すとき、そのセグメントで示されている確認応答番号は、対応するシーケンス番号未満のデータを全て受信済みであることを示している。送信側はペイロードの先頭バイトのシーケンス番号をそのセグメントのシーケンス番号として設定する。受信側は次に受信することを期待しているバイトのシーケンス番号を確認応答番号に設定して確認応答を返す。例えば、送信側が4バイトのペイロードをシーケンス番号 100 で送信する場合、そのペイロードの4バイトのシーケンス番号は順に 100、101、102、103 である。受信側がこのセグメントを受信すると、その確認応答での確認応答番号は 104 となり、次のパケットで送られてくるペイロードの先頭バイトのシーケンス番号となっている。
累積確認応答に加えて、受信側は選択確認応答でさらなる情報を送ることができる。
送信側がネットワーク内でデータが失われたと判断した場合、データの再送を行う。

誤り検出

後述の#検査合計の計算も参照。
シーケンス番号と確認応答は、パケットの重複、喪失パケットの再送、データの順序通りの並べ替えなどを扱っている。受信したパケットの内容が正しいことを確認するため、TCPには検査合計フィールドがある。検査合計フィールドは設定必須の項目であり省略できない。
TCP検査合計は、現在の標準から見れば弱い。データリンク層のビット誤り率が高ければ、TCP検査合計とは別の誤り検出訂正機能が必要である。TCP/IPの下層であるデータリンク層には一般にCRCなどのもっと強力な検査機構があり、TCP検査合計の弱さを一部補っている（例えば、PPPやイーサネット）。しかし、だからといって16ビットのTCP検査合計が無駄というわけではない。実際、CRCで保護された通信路でパケットに誤りが残ることはよくあるが、エンドツーエンドの16ビットTCP検査合計がそういった単純な誤りを捉えている。これはエンドツーエンド原理が機能している例である。

フロー制御

TCPはエンドツーエンドのフロー制御プロトコルを使い、送信ペースが受信側にとって速すぎる状態になるのを防いでいる。様々な性能の機器が接続されたネットワークでは、フロー制御は欠かせない機構である。例えば、PCから性能の劣るPDAにデータを送る場合、PDAの性能に合わせて送信ペースを調整する必要がある。
TCPはスライディングウィンドウによるフロー制御を採用している。各TCPセグメントについて、受信側は「ウィンドウサイズ」フィールドで、そのコネクション用のバッファの空き容量に相当する今後受信可能なデータの量（バイト単位）を示す。送信側は確認応答を待ち合わせるまでに、そのフィールドで指定された量までのデータを送り、新たな確認応答でウィンドウサイズ・フィールドを確認してさらに送信できるデータ量を更新する。
受信側がウィンドウサイズを0としたとき、送信側は送信を停止してタイマ (persist timer) を起動する。このタイマは受信側のウィンドウサイズの更新セグメントが喪失してデッドロック状態になるのを防ぐためのものである（受信側がウィンドウサイズを更新しないと送信を再開できないため）。タイマがタイムアウトすると、送信側は小さなパケットを送り、その確認応答で受信側のウィンドウサイズが回復したかを調べる。
受信側での受信データの処理が遅いと、ウィンドウサイズの指定は小さいままとなる。これをSilly Window Syndrome (SWS)と呼び、送信側は1度に数バイトのデータしか送れなくなり、TCPヘッダの方が大きな割合を占めるため転送効率が極端に低下する。そのような状況に陥らないようにするためのウィンドウ・アルゴリズムが RFC 813 (Window and acknowledgement strategy in TCP) に記載されている。

輻輳制御

TCPは高性能を達成し輻輳崩壊（ネットワーク性能が数桁のオーダーで低下する現象）を防ぐため、輻輳制御機構をいくつか備えている。ネットワークに流入させるデータレートを制御し、崩壊のきっかけとなるようなレート未満でデータを送るよう保つ。また、おおまかに最大最小公平なフロー割り当てを目指す。
送信データへの ACK (確認応答)の有無は、送信側でネットワークの状態を推測する材料となる。これをタイマと組み合わせ、データのフローの振る舞いを変化させることができる。これを一般に輻輳制御またはネットワーク輻輳回避などと呼ぶ。
最近のTCP実装では、スロースタート、輻輳回避、TCP高速再送アルゴリズム、ファストリカバリ(en, RFC 5681) という4つの相互にからみあったアルゴリズムを使用している。
スループットをあげるため輻輳しない限界まで送信側はスライディングウィンドウを大きくする必要があるが、ウィンドウサイズを調整する輻輳回避アルゴリズムは長年研究されている。一覧は w:TCP congestion avoidance algorithm を参照。かつては、輻輳するとパケットロスが発生することを利用し、パケットロスをベースにした TCP Reno およびそれを改良した TCP NewReno (RFC 3782) がよく使われていたが、現在では、送信側のスライディングウィンドウにどれだけの時間とどまっていたかを元にしたアルゴリズム (Delay-based Congestion Avoidance) が中心になっており、Microsoft Windows では、Windows Vista 以降は、Compound TCP が採用され、Linux では 2.6.8〜2.6.18 は BIC TCP が、2.6.19 以降は CUBIC TCP が使われている。
さらに送信側には「再送タイムアウト (RTO)」があり、送信してから確認応答が戻るまでの時間であるラウンドトリップタイム (RTT) を推算し、ばらつきも考慮して設定する。このタイマの動作は RFC 2988 で規定されている。RTTの推算には微妙な点がある。例えば、再送パケットのRTTを計算する場合は注意しなければならず、一般にカーンのアルゴリズムやTCPタイムスタンプ（RFC 1323 参照）を使う。個々のRTTの標本から時系列で平均をとり、ジェイコブソンのアルゴリズムを使って Smoothed Round Trip Time (SRTT) を生成する。最終的にSRTT値がRTTの推算に使われる。
TCPを拡張して、喪失を高信頼に扱ったり、誤りを最小化したり、輻輳を制御してより高速化しようという試みが今も行われている。

遅延送信

最大セグメントサイズ以下の小さなパケットをばらばらと送るのは非効率なので、送信を遅延し、それらを1つのTCPパケットにまとめるのが、Nagleアルゴリズムである。同様に、複数のACKを1つにまとめるのが、TCP遅延ACKである。どちらも、送信を遅延させるという点においては同じだが、相互に影響し合い、遅延が増大するという問題があり、詳細はNagleアルゴリズムを参照。

最大セグメントサイズ

最大セグメントサイズ (MSS) はバイト単位で指定され、単一のセグメントとして受信可能な最大データ量を示す。性能を最大限発揮するにはIPフラグメンテーションを十分防げる程度に小さくする必要がある。IPフラグメンテーションが行われると、パケット喪失時の再送に時間がかかることになる。一般にコネクション確立時にMSSオプションを使って双方のMSSを通知するので、適切なMSSを決めるにはデータリンク層の Maximum Transmission Unit (MTU) から導出したMSSを通知すればよい。さらに送信側は経路MTU探索を使うことができ、通信相手との間にある経路でMTUが最小の部分を推定し、それを使ってMSSを動的に調整しIPフラグメンテーションを防ぐことができる。
MSS通知は「MSSネゴシエーション」とも呼ばれる。ネゴシエーションというと送信側と受信側が交渉して合意に達するかのように思われるが、実際には異なり、送信する方向によってそれぞれ異なるMSSが設定可能である。これは例えば一方がメモリ容量が小さいため、バッファ領域を大きくとれない場合などに起きる（発見したパスMTUより小さいこともありうる）。

選択確認応答

もともとのTCPプロトコルで採用されている累積確認応答方式を使うと、パケットを喪失したときに非効率になる可能性がある。例えば、10,000バイトのデータを10個のTCPセグメントで送信し、その最初のパケットが喪失したとする。もともとの累積確認応答プロトコルでは、受信側は1,000から9,999までのバイトは受信成功、ただし0から999までのバイトを含む先頭パケットの受信に失敗したという風に伝えることができないので、送信側は10,000バイト全体を再送しなければならない。
このため RFC 2018 で「選択確認応答 (SACK)」オプションが追加された。これは、通常の累積確認応答とは別に、受信側が不連続なブロックを正しく受信したという確認応答を返せるようにしたものである。選択確認応答にはオプション部分にいくつかのSACKブロックを指定し、SACKブロックには正しく受信できた連続な範囲のシーケンス番号の開始点と終了点を指定する。例えば、先ほどの例では 1000 と 9999 のシーケンス番号をSACKオプションで示せばよい。すると送信側は 0 から 999 までのバイトを含む最初のパケットだけを再送する。
SACKオプションの拡張として RFC 2883 で定義されたデュプリケートSACK (D-SACK) オプションがある。パケットの順序がばらばらになると、送信側への確認応答も順序どおりにならないため送信側でパケット喪失と勘違いし、喪失したと思われるパケットを再送することがあり、同時にネットワーク輻輳を防ぐため送信ペースを落とす。このとき、受信側が D-SACK オプションで再送パケットが重複していることを通知すれば、遅くなっていた送信ペースを元に戻すことができる。
SACKオプションは必須ではなく、両者がサポートしている場合だけ使われる。これはコネクション確立時に調整される。SACKオプションは主なTCPスタックでサポートされており、広く使われている。選択確認応答は Stream Control Transmission Protocol (SCTP) でも使われている。

ウィンドウスケーリング

広帯域ネットワークをより効率的に使うには、TCPウィンドウのサイズを大きくする必要がある。TCPヘッダのウィンドウサイズのフィールドは16ビットで、2バイトから65,535バイトまでしか設定できない。
ウィンドウサイズ・フィールドは拡張できないので、スケールファクタが導入されている。RFC 7323 で定義されているウィンドウスケール・オプションを使えば、最大ウィンドウサイズを 65,535 バイトから 1 ギガバイトに拡張できる。ウィンドウサイズのスケールアップはTCPのチューニング (en) に必須の要素である。
ウィンドウスケール・オプションは3ウェイ・ハンドシェイクの際にしか使われない。ウィンドウスケール・オプションのオプション値は、16ビットのウィンドウサイズ・フィールドの値を左にシフトするビット数を表している。ウィンドウスケールの値は0（シフトしない）から14まで指定でき、通信の双方向で別々に設定できる。どちらの方向もSYNセグメントのオプションとして通知する。
一部のルーターやファイアウォールは、このスケールファクタを転送時に書き換えることがある。すると送信側と受信側でウィンドウサイズの認識が異なることになり、トラフィックが不安定になって、非常に低速になることがある。

帯域外データ

ストリームが完了するのを待たずに、キューイングされたストリームに割り込むことができる。この場合、緊急 (urgent) と指定したデータを使う。それによって受信側プログラムが緊急データをすぐさま処理すべきであることを知らせる。その処理が終了すると、もとのストリーム・キューの処理を再開する。例えば、リモートログインのセッションにTCPを使っているとき、ユーザーが実行中のプログラムをアボートさせるキーシーケンスを送るときなどに使われる。プログラムが暴走したときなど、そのプログラムの出力を待っているのではなく、強引にアボートさせたいときに必須となる。
帯域外データの概念は現在のインターネット向けの設計ではない。緊急ポインタは相手ホストでの処理を変えるものであって、ネットワーク上の処理は何も変わらない。緊急ポインタのあるセグメントがリモートホストに到着したとき、若干異なる2つのプロトコルの解釈があり、単一バイトの帯域外データしか信頼できないという状況になっている。そのため滅多に使われず、実装も貧弱になる傾向がある。

強制的データ送出

通常、TCPは送信すべきデータが最大セグメントサイズ (MSS) まで溜まるか、200ミリ秒経過するまで待つ（Nagleアルゴリズムで小さいメッセージを単一パケットにまとめようとするため）。これは例えばファイル転送のような一定の送信が要求される場合に問題となることがある。例えば、送信ブロックが一般的な4KBで、MSSも一般的な1460バイトだとする。すると1ブロックが3セグメントで送信され、最後の1セグメントはMSSに満たないことになる。すると、2パケットまでは約1.2ミリ秒で送信され、1176バイトの3パケット目は197ミリ秒待ってから送信ということになる。
Telnetの場合、ユーザーがキーを押下するたびに通信先からエコーバックされて画面に文字が表示される。すると、1文字押下するたびに200ミリ秒待たされることになり、非常にストレスになる。
この場合、ソケットのオプション TCP_NODELAY を使ってデフォルトの200ミリ秒の送信遅延を変更することができる。
RFCには PSH フラグを使って「受信側TCPスタックでそのデータを即座にアプリケーションに送る」という機能が定義されている。しかしソケットにはこれを制御するインタフェースがなく、プロトコルスタックの実装に任されている。

コネクション終了

コネクション終了フェーズは多くの場合「4ウェイ・ハンドシェイク」を使い、コネクションの双方がそれぞれ独立に終了できる。一方がコネクションを終了したい場合、FINセグメントを送信し、相手がそのACKを返す。相手も同様にFINを送ってACKを受信することでコネクションを終了する。両方のFIN/ACK交換が済むと、最後にACKを送った側（先にFINを送った側）がタイマを設定してタイムアウトするまで当該ポートを別のコネクションに再利用できないようにする。これによって配送が遅れていたパケットが新たなコネクションで受信されて混乱するのを防ぐ。
コネクションは「ハーフオープン」という状態にもでき、一方だけ終了していても、もう一方はデータを送り続けることができる。終了した側はもう一方が終了するまで受信可能の状態を継続する。
コネクション終了を3ウェイ・ハンドシェイクで行うこともでき、ホストAのFIN送信に対してホストBが FIN+ACK で応答し、ホストAがACK応答する。実際にはこれが最も一般的である。
両方から同時にFINセグメントを送りあい、双方がACKを返すということもありうる。FIN/ACKシーケンスが並行して行われるため、2ウェイ・ハンドシェイクと呼ぶこともできる。

脆弱性

TCPは様々な方法で攻撃される可能性がある。TCPの完全なセキュリティアセスメントの結果は、認識されていた問題の考えうる対策と共に2009年に公表され、その後もIETF内で進められている。

DoS攻撃

IPスプーフィングを使い、悪意を持って作ったSYNパケットを繰り返し送信することで、偽の接続に対処するために対象サーバの多大な量のリソースを消費させることができる。これを SYN flood 攻撃と呼ぶ。この問題への対策として提案された方法として、SYN cookies や暗号的パズルがある。Sockstress も類似の攻撃法だが、システムのリソース管理によって効果を和らげることができる。オンラインマガジン Phrack 66号では、TCPの Persist Timer に存在する脆弱性を利用した改良型DoS攻撃の分析を行っている。

コネクション乗っ取り

TCPセッションを盗聴できパケットをリダイレクトできる攻撃者は、TCPコネクションを乗っ取ることができる。その場合、攻撃者は進行中の通信からシーケンス番号を読み取り、ストリームにおける次のセグメントを装った偽のセグメントを作る。そのような簡単な乗っ取りで、通信中の一方に1つのパケットを誤って受け取らせることができる。受け取ったホストが余分なセグメントへの確認応答をコネクションのもう一方に返すと、同期が失われる。ARPまたはルーティング攻撃を組合わせることで、乗っ取ったTCPコネクションの制御を完全に奪うことができる。
RFC 1948 が登場する以前は異なるIPアドレスを真似ることは難しくなく、初期シーケンス番号は容易に推測可能だった。そのため攻撃者はARP/ルーティング攻撃を併用することなく、適当な一連のパケットを受信者に送信し、異なるIPアドレスからのものだと信じさせることができた。その際、偽装したIPアドレスの本来のホストがダウンしていれば十分であり、Dos攻撃でそのホストをダウンさせればよかった。以上のような理由から、初期シーケンス番号のランダムな選択が行われるようになった。

TCPポート

TCPはポート番号をホスト上の送受信アプリケーションの識別に使う。TCPコネクションの両端に16ビット符号なしのポート番号 (0-65535) が対応付けられており、一部のポート番号は送受信アプリケーションによって予約されている。受信したTCPセグメントは、送信元IPアドレスと送信元ポートと宛先IPアドレスと送信先ポートの組み合わせによって特定のTCPコネクションに属すると識別される。異なる送信元ポートから同じ送信先ポートへのコネクションを複数同時に確立できるので、サーバは複数のクライアントに対して同時にサービスを提供できる。
ポート番号は大きく3つに分類されており、ウェルノウン (well-known)、レジスタード (registered)、ダイナミック/プライベート (dynamic/private) がある。ウェルノウンポート番号は Internet Assigned Numbers Authority (IANA) が割り当てを行っており、主にシステムレベルや重要なプロセスで使われている。サーバとして動作する有名なアプリケーションは、それらのポートを使いコネクション確立要求を待ち受けているのが一般的である。例えば、FTP (20, 21)、SSH (22)、TELNET (23)、SMTP (25)、HTTP (80) などがある。レジスタードポート番号は一般にエンドユーザー用アプリケーションが送信元のエフェメラルポートとしてサーバに接続するのに使うが、サードパーティが登録した名前を持ったサービスの識別にも使われている。ダイナミック/プライベートポート番号もエンドユーザーのアプリケーションで使えるが、一般にそのような使い方は少ない。ダイナミック/プライベートポート番号は、それを使っている特定のTCPコネクションでしか意味を持たない。

発展

TCPは複雑なプロトコルである。長年重大な改良が実施されたり提案されたりしてきたが、1974年に RFC 675 で最初の仕様が登場し、1981年9月に RFC 793 でバージョン4が登場して以来、基本的動作はほとんど変わっていない。RFC 1122 (Host Requirements for Internet Hosts) はTCPプロトコルの実装時の要求仕様を何点か明確にし、近年最も重要なTCP関連のRFCの1つである RFC 2581 (TCP Congestion Control) は輻輳を防ぐための新たなアルゴリズムを提示している。2001年、RFC 3168 で明示的輻輳通知 (ECN) が提示された。
当初のTCP輻輳回避アルゴリズムは "TCP Tahoe" と呼ばれているが、代替アルゴリズムも多数提案されている（TCP Reno、TCP Vegas、FAST TCP、TCP New Reno、TCP Hybla など）。
Multipath TCP (MPTCP)はIETFで近年進行中の改良で、リソース利用効率と冗長性を高めるためにTCPコネクションを複数経路にする試みである。Multipath TCP による冗長性は、無線ネットワークでリソースの統計多重化を可能にし、TCPのスループットを劇的に高める。Multipath TCP はデータセンター環境にも性能面の利点をもたらす。Multipath TCP のリファレンス実装がLinuxカーネル向けに開発されている。
TCP Cookie Transactions (TCPCT) は2009年12月に提案された拡張で、サーバをDoS攻撃から守ることを意図している。SYN cookies とは異なり、TCPCTはウィンドウスケーリングなどの他のTCP拡張と共存できる。TCPCTは、短命なTCPコネクションをサーバが多数処理しなければならないDNSSECでの必要から設計された。
tcpcrypt は2010年7月に提案された拡張で、TCP自身で直接暗号化するものである。透過的に動作可能なように設計されており、設定変更は不要である。TLS (SSL) とは異なり、tcpcrypt 自体は認証機構を持たないが、そのための簡単なプリミティブをアプリケーションに提供する。2010年現在、IETF による最初のドラフトが公表されており、いくつかの主要プラットフォームでの実装が存在する。

無線ネットワークでのTCP

TCPは有線ネットワーク向けに最適化されてきた。一般にパケット喪失はネットワーク輻輳の結果と判断され、予防のために輻輳ウィンドウサイズが大幅に縮小される。しかし無線の場合、減衰、影に入る、ハンドオーバーなどの無線特有の原因でパケットを喪失することがあり、輻輳が原因とは限らない。無線パケット喪失による（誤った）輻輳ウィンドウサイズ縮小後、輻輳回避のための保守的なウィンドウサイズの縮小も行われる可能性がある。これにより無線リンクの効率が低下する。このような問題への対策が広く研究されている。提案されている対策としては、エンドツーエンド型の対策（クライアントとサーバの修正が必要）とリンク層の対策（RLPなど）とプロキシを使った対策（端点以外のネットワークの何らかの変更が必要）がある。

デバッグ

LANアナライザはネットワークリンク上のTCPトラフィックをインターセプトできる機器で、リンク上を通るパケットの内容を表示でき、ネットワーク、プロトコルスタック、TCPを使っているアプリケーションのデバッグに有効である。一部の実装ではソケットの setsockopt() で SO_DEBUG オプションを指定でき、全パケット、TCPのステータス、ソケット上のイベントなどを出力でき、デバッグに有効である。他に、netstatもデバッグに使われる。

代替となる選択肢

TCPの多くの用途は適切とはいえない。（少なくとも通常の実装での）最大の問題は、喪失パケットの再送を受信してからでないと受信済みの後続のパケットをアプリケーションで利用できない点である。特にストリーミング、オンラインゲーム、VoIPなどのリアルタイム型アプリケーションで重要な問題であり、データの順序性よりも適時性が重要である。
歴史的・性能的理由により、ストレージエリアネットワーク (SAN) はTCP/IPよりもファイバーチャネルプロトコルを採用することが多い。
組み込みシステムでも、ネットワークブートや多数のクライアントからの簡単な要求を受け付けるサーバ（例えばDNSサーバ）でTCPの複雑さが問題となる可能性がある。さらには、STUNなどの NAT traversal 技法では相対的に複雑なTCPを使わずに、遥かに単純な方法で実現している。
一般にTCPが適さない場合は User Datagram Protocol (UDP) を使用する。UDPはTCPと同様にアプリケーション多重化と検査合計機構を提供するが、ストリームの構築や再送を行わず、アプリケーションにそういった機能の実装を任せている。
SCTPは、TCPとよく似たストリーム指向のサービスを提供するプロトコルである。TCPより新しくさらに複雑であり、広く普及したとは言い難い。しかし、信頼性とリアルタイム性を同時に必要とする用途を意図して設計されている。
TCPは広帯域環境でも問題を抱えている。TCP輻輳回避アルゴリズムは、送信者が事前にわからない場当たり的な環境ではうまく機能するが、通信パターンが予測可能な環境では Asynchronous Transfer Mode (ATM) のようなタイミングに基づくプロトコルの方がオーバーヘッドが小さく、うまく機能する。

検査合計・オフロード

多くのTCP/IPスタック実装では、ネットワークカードによる自動検査合計計算を補助的に使うオプションを用意している。これによりCPUサイクルを検査合計計算に費やすコストを低減でき、ネットワーク性能を向上させることができる。
なお、送信時に検査合計計算をネットワークカードに任せていると、LANアナライザが検査合計エラーを検出することがある。