TCP
TCPは"Transmission Control Protocol"の略で、トランスポート層のプロトコルの一つです。TCPは、信頼性の高い通信を提供するために設計されており、以下のような特徴を持っています。
コネクション指向: 通信を開始する前に、接続を確立する必要があります。これにより、データの送受信が確実に行われます。
信頼性: データの順序が保証され、パケットの損失や重複が検出され、再送信が行われます。
TCPの概要
それではTCPの概要について確認しましょう。
TCPでは情報は連続して入出力されるということで、UDPにおける『データグラム』とは違う『ストリーム(stream)』という概念で扱われます。 ストリームは、データの連続的な流れを表し、TCPはこのストリームを確実に送受信するための機能を提供します。
ストリームには順序(最初に送信されたデータが最初に届く)を保証する必要があります。
ストリームは、データの断片化を行わず、連続したデータとして扱います。つまり、アプリケーション層でのデータの分割や結合は必要ありません。
分割は必要であればTCPの層が行うため、アプリケーション側では考えなくて良いということです。
ストリームは、データの到達確認を行い、パケットの損失や重複を検出し、再送信を行います。これにより、信頼性の高い通信が実現されます。
順序の保証
TCPにおいて、送出されるデータは順序が保証されるようになっています。 これは、断片化が発生する際に『この断片はストリームの何番目』という情報を付与して送信されるためです。
受信側はこの情報を利用して、受信したデータを正しい順序で再構築します。
信頼性の保証
TCPは、信頼性の高い通信を提供するために、以下のような機能を持っています。
再送信: パケットが損失した場合、TCPはそのパケットを再送信します。これにより、データの完全性が保証されます。
フロー制御: TCPは、送信側と受信側のバッファサイズを考慮して、データの送信速度を調整します。これにより、受信側が処理できる範囲内でデータが送信され、輻輳を防ぎます。
コネクションの確立と終了
信頼性のひとつとしても考えられますが、どこから通信が開始され、どこで終了するのかが明確にしておかないといけません。 そのために、接続(コネクション)の確立と終了の際に、3ウェイハンドシェイクと呼ばれる手順が用いられます。
接続時の確立フロー
sequenceDiagram participant Client participant Server Client->>Server: SYN (接続要求) Server->>Client: SYN-ACK (接続承認) Client->>Server: ACK (接続完了)
接続の確立の前にある意味確認とも言える『接続要求』の信号を送信します、これをSYNと呼びます。 受け取った相手側は双方向通信を行うため、ACKと呼ばれる『承認』の信号と共にSYNも返します(SYN-ACK)。 受け取った側(すなわち本来の接続要求側)も、ACKを返すということになります。 これにより双方から通信の承認が下り、双方向回線が開くということになります。
接続終了のフロー
sequenceDiagram participant Client participant Server Client->>Server: FIN (接続終了要求) Server->>Client: ACK (接続終了承認) Server->>Client: FIN (接続終了要求) Client->>Server: ACK (接続終了承認)
接続を終了する際には、FINと呼ばれる『ここで通信は終わります』に相当する信号を送信します。これは『接続終了要求』の意味を持ちます。 こちらでも、受け取った側からACK(承認)と共にFINを返します。 送信元もこれに応じてACKを返すことで、双方のFINが成立して切断となります。
もちろん実際にはFINの処理が行われる前に『強制的に回線が切られる』などの問題も起こりえますが、正常な終了という意味ではこの流れとなっています。
フロー制御
フロー制御は、TCPの重要な機能の一つであり、送信側と受信側の間でデータの流れを調整する役割を果たします。これにより、受信側が処理できる範囲内でデータが送信され、輻輳を防ぎます。
TCPでは、ウィンドウサイズという概念を用いてフロー制御を実現しています。ウィンドウサイズは、送信側が一度に送信できるデータの量を制限するもので、受信側のバッファサイズに基づいて動的に調整されます。
具体的には、受信側は自分のバッファの空き状況を送信側に通知し、送信側はその情報をもとにデータの送信速度を調整します。これにより、受信側がオーバーフローすることなく、スムーズなデータ転送が実現されます。
この部分をいかに効率的に行うかというのが輻輳制御(ふくそうせいぎょ)というものです。 輻輳制御のアルゴリズムなどまではこの授業では取り扱いません。
TCPのヘッダー構造
以下の図は、基本となるTCPのヘッダー構造です。
classDiagram class TCPHeader { +Source Port(送信元ポート番号): 16bit +Destination Port(宛先ポート番号): 16bit +Sequence Number(シーケンス番号): 32bit +Acknowledgment Number(確認応答番号): 32bit +Data Offset(データオフセット): 4bit +Reserved(予約領域): 6bit +Flags(コントロールフラグ): 6bit +Window Size(ウィンドウサイズ): 16bit +Checksum(チェックサム): 16bit +Urgent Pointer(緊急ポインタ): 16bit }
それぞれを簡単に説明します。
Source Port(送信元ポート番号): 送信元のアプリケーションが使用するポート番号です。
Destination Port(宛先ポート番号): 宛先のアプリケーションが使用するポート番号です。
Sequence Number(シーケンス番号): 送信されたデータの順序を識別するための番号です。これにより、受信側はデータの順序を正しく再構築できます。
Acknowledgment Number(確認応答番号): 受信側が受け取ったデータの最後のシーケンス番号を示します。これにより、送信側はどのデータが受信されたかを確認できます。
Data Offset(データオフセット): ヘッダーの長さを示すフィールドで、ヘッダーのサイズを4の倍数で表します。
ここだけは少しややこしくて、4バイトを1つのかたまりと考えてn倍という形で表現します。
標準的なTCPヘッダは20バイトのため、ここの値は(20/4で)5です。
オプションがある場合は32ビット単位のパディングで入力するキマリのため、必ず4の倍数です。
Reserved(予約領域): 将来の拡張のために予約されたビットです。
Flags(コントロールフラグ): TCPの制御フラグを示すビットフィールドで、接続の確立や終了、データの確認応答などの状態を示します。
Window Size(ウィンドウサイズ): 受信側のバッファサイズを示し、送信側が一度に送信できるデータの量を制限します。
Checksum(チェックサム): データの整合性を確認するためのフィールドで、送信されたデータに対するチェックサムが含まれます。
Urgent Pointer(緊急ポインタ): 緊急データの位置を示すためのフィールドで、緊急データが含まれている場合に使用されます[1]。
シーケンス番号により、上位レイヤーから送られたデータが分割されている状態において『どの位置か』がわかる仕組みとなっています。 そして確認応答番号により『受信側がどのデータを受け取ったのか』がわかる仕組みとなっています[2]。
再送について
TCPにおいては、送信側が『受信側がどこまで受信できているか』を確認応答番号で把握します。 そのため、受信側が確認応答を返さない場合、送信側はそのデータが失われたと判断し、再送信を行います。
再送が発生するまでの時間(いわゆる『タイムアウト』)をどうするかはOSによる違いがあります。 一般的なUNIXでは、初期のタイムアウトを0.5秒単位で制御しており、タイムアウトは0.5秒の整数倍とされていることが多いです。ただし最初は多め(6秒程度)に設定されていることが多いです。
再送しても確認応答が戻らない場合は、繰り返し送信していきますが、タイムアウトが倍々となっていきます(0.5秒→1秒→2秒→4秒…)。さらにタイムアウトが増えていくことで、最終的には『再送をやめる』となります。 回線の正常な切断が行われなければ、いずれ再送が起きなくなり、回線は切れた状態となります。
ウィンドウサイズとバースト送信
ひとつパケットを送るたびにACKを待っていると非常に効率が悪いため、実際にはある程度まとめて送信を行っています。 このまとめて送る際に重要となるのがウィンドウサイズです。 確認応答パケットにあるウィンドウサイズを利用して、TCPパケットの分割された状態(セグメント、分割されたIPパケットとざっくり考えておくとよい)をまとめて送信します。 このウィンドウサイズは、受信側のバッファサイズに基づいて動的に調整されます。送信側は、ウィンドウサイズを考慮して、同時に送信できるデータの量を制限します。
この場合の確認応答は『受信の完了したデータの最後のシーケンス番号(+1)』となります。 もし途中のシーケンスが損失した場合は多少問題が発生します。
ACKにより足りないシーケンス番号が返されるため、それ以降の再送となります。
そもそもACKが帰ってこない場合は、まとめて送り直しということになります。
TCPの利用例
TCPは、信頼性が重要なアプリケーションで広く使用されています。以下は、TCPの利用例です。
ウェブブラウジング: HTTPやHTTPSプロトコルは、TCPを基盤として動作します。ウェブページのデータが正確に順序通りに送信されることが求められます。ただし最近はQUICというプロトコルに置き換えられる状況が出ています(HTTP/3)。
電子メール: SMTP、POP3、IMAPなどの電子メールプロトコルは、TCPを使用して信頼性の高いメールの送受信を実現します。
ファイル転送: FTP[3](File Transfer Protocol)やSFTP(Secure File Transfer Protocol)などのファイル転送プロトコルは、TCPを使用してファイルの正確な転送を行います。