基本は確実に伝達することでした。
それを実現するために、
データを送る側では「シーケンス番号」を付けて送ります。
相手側では、次に受け取るべき情報となる確認応答番号
(ACK番号=受け取った「シーケンス番号」+受信データ量)を、
とACKフラグをセットしたセグメントで応答する規則でした。
そしてこの返ってきた情報から、正しく送れたか判断し、返ってこないなら再送します。
(この判断はタイムアウトで行われます。)
さて、送信データに対する応答セグメントを待っていると遅くなるので、
相手側が「まとめて受信可能なセグメント」を、応答セグメントを待たずに送信できる規則があります。
自身がどれだけのセグメントをまとめて受けられるかは、
TCPヘッダー内のウインドウサイズに指定して、
ACKのセグメントで応答します。
(このウインドウは、広告ウインドウ(advertised window)と呼ばれます。)
これにより、適切な数のセグメントを連続して送ることができます。
(このような制御はフロー制御と呼ばれます。)
また、「ウインドウプローブ」というセグメントで、相手の広告ウインドウサイズの情報を要求できます。
これは定期的に送信され、受信側は「ウインドウ更新通知セグメント」で応答する仕組みになっています。
(これを受信した送信側では、以降でその数のセグメントを連続して送ることができます。)
ここの連続したセグメント受信において、途中のセグメントを受け取れなかった場合はどうすのでしょうか?
それは、失ったセグメントの一つ前のセグメント
に応答するセグメント(次に送って欲しいシーケンス番号=失ったセグメント) を重複して、
受信できたその後の応答セグメントの代わりに返す規則になっています。
(⇒重複確認応答や重複ACKと呼ばれます。)
データの送り手では、重複ACKを受けとった時、タイムアウトを待たずに失われたセグメントが分かるので、
そのセグメントを再送します。この転送は「高速再転送」と呼ばれます。
通信路の混雑の状態によって、セグメントの送る量を制御します。
これは相手側の広告ウインドウサイズではなく、
送信側で持つパラメタで輻輳ウインドと呼ばれます。
セグメントの喪失の検出でウインドサイズを減らし、
検出されないなら増やす制御です。
接続直後は混雑状態が分からないので、
初期の輻輳ウインドは1のセグメントで連続送信はしません。
ACKを受け取ったら1増やした2にします。
2つのセグメントを連続して送信して、
それに対するACKが2つ戻った場合は、
それぞれで1づつ増やすので4の輻輳ウインドとなります。
指数関数的に増えていきますが、初期は1なので「スーロースタート」呼ばれる制御です。
そして、予め決められた「スロースタートしきい値」に輻輳ウインドサイズが達すると、
「輻輳回避」と呼ばれるアルゴリズムに変ります。
これは、1回のACK応答に対して「1÷輻輳ウインドサイズ」を割った値だけ増やします。
そして、
重複ACKのエラーで輻輳ウインドサイズを「スロースタートしきい値」+3に戻し、
タイムアウトエラーで1に戻して「スーロースタート」に戻します。
なお、実際の送信で使われるウインドウは、輻輳ウインドと広告ウインドウのどちらか小さい方が使われます。
最大セグメント長 MSS(Maximum Segment Size)
TCPセグメントに格納されるデータの最大バイト長のことです。
TCPは上位アプリケーションからのデータを複数に分割しますが、
その分割後のデータ長のです。TCPヘッダの大きさは含まれません。
MSSの決定は、TCPのコネクション確立時です。
確立時の送信側のTCPでは、
データリンクの最大転送範囲(MTU:Maximum Tranmission Unit)の値から、
可能なMSSの値を計算して、SYNセグメントで相手先に通知する形態です。
例えば、イーサネットに接続している場合のMTUは1500バイトなので、
IPヘッダの20バイトとTCPヘッダの20バイトを除いた1460バイトを、MSSとします。