TCP コネクション

July 19, 2018

TCP 通信の 3 つのフェーズ

TCP 通信は、次の 3 つのフェーズがある。

1. コネクション確立フェーズ

コネクション確率フェーズは 3 つのパケット (SYN 、SYN/ACK 、ACK) のやり取りからなる。(3 Way Handshake)
このやり取りを通して、互いの IP アドレス、ポート番号、シーケンス番号、確認応答番号、ウィンドウサイズ、MSS などを交換し合い、以降の通信に備える。
以下の図は、ホスト A からホスト B へコネクション確率が要求される場合の、コントロールフラグ、シーケンス番号呼び確認番号の推移を示している。

f:id:shiro_kochi:2018××××××××:plain:w100:left

(1). FLAG は SYN となる。シーケンス番号はランダム値 (ここでは 10000) であり、送信後、ホスト A はシーケンス番号に 1 を加算して保存する。

(2). FLAG は SYN/ACK となる。シーケンス番号はランダム値 (ここでは 20000) であり、確認応答番号は (1) におけるシーケンス番号に 1 を加算した値となり、これは 1. のパケットを正常に受信したことを意味している。

(3). FLAG は ACK となる。シーケンス番号は (1) のシーケンス番号に 1 を加算した値となっており、これは 1 のパケットを正常に送信したことを意味する。また、確認応答番号は (2) のシーケンス番号に 1 を加算した値となっており、これは (2) のパケットを正常に受信したことを意味している。

2. 通信フェーズ

送信側のアプリケーションデータは、受信側のアプリケーションに順番通りに受信される。データのバイト数が MSS より大きい場合、MSS に収まるよう、複数個のパケットに分割されて送信される。この時、相手に順番通りにデータが送られることを保証するため、シーケンス番号と確認応用番号が用いられる。

データを送信した後、送信側は自分のシーケンス番号に送信データのバイト数を加算した値を保持する。データを受信したとき、受信側は自分が保持しているシーケンス番号とパケットの確認応答番号、及び自分が保持している確認応答番号とパケットのシーケンス番号がともに一致していることを確認する。
正常に受信したことが確認できると、自分の確認応答番号に受信データのバイト数を加算した値を保持する。

以下の図は通信フェーズにおける、シーケンス番号及び確認応答番号の推移を示している。(ホスト A から 1000 バイト、ホスト B から 2000 バイトを送信している。)
なお、イーサネットの場合、MSS が 1460 バイトなので、2000 バイトを送信する際には 2 パケットを要する ((3), (4))。また、(2)、(5) は確認応答パケットであり、送信データはない。
連続転送が可能なデータの範囲は、受信した確認応答パケットに格納されている確認応答番号とウィンドウサイズの値から決定される。つまり、確認応答番号を起算点としたウィンドウサイズ分が、連続転送可能なデータの範囲となる。この範囲は、確認応答パケットを受信するたびに更新される。

f:id:shiro_kochi:2018××××××××:plain:w100:left

通信フェーズでエラーが発生した場合、再送制御が行われ、大きく分けて「再送タイムアウトによる方法」と「高速再転送よる方法」の二種類が存在する。

再送タイムアウトによる方法

送信したパケットに対する ACK パケットが返ってこなかった場合、途中経路でパケットが消失したか、受信側で何らかのトラブルが発生して ACK を返せなかったためと考えられる。このとき、送信側は一定期間 (RTO: Retransmission Time Out) 待ってからパケットを再送する。
再送が繰り返し行われる場合、途中経路で輻輳が発生していることが考えられる。そのため RTO は再送のたびに 2 倍となり、最大で 64 秒となる。

高速再転送による方法

連続転送している状況下において、特定の TCP セグメントだけが欠落した場合、受信ホストから送信ホストに対して、当該 TCP セグメントの再送を要求する仕組みとなる。この際、3 回以上連続して ACK を再送する。
以下に例を示す。

f:id:shiro_kochi:2018××××××××:plain:w100:left

(2) のパケットが何らかの理由により送信されなかった場合、(4) にあるように、SN/AN は更新せずに ACK を返す動きとなる。
この ACK が 3 回続いた時点でホスト A は送信できなかったセグメントを再送し、既に (1)、(3)、(5)、(7) の分のセグメントは受信済みなので、(9) の再送されたセグメントを受け取った時点で、AN: 17301 として ACK を返却する、という動作となる。

コネクション切断フェーズ

コネクション切断フェーズは、4 つのパケット (FIN/ACK 、ACK 、FIN/ACK 、ACK) からなる。(タイムアウト等、例外は存在する)
以下の図は、コネクション切断フェーズにおける、コントロールフラグ、シーケンス番号及び確認応答番号の推移を示している。

f:id:shiro_kochi:2018××××××××:plain:w100:left

フロー制御と輻輳制御

TCP ではコネクション確立フェーズ中に、ホストが互いにウィンドウサイズの最大値を通知し合う。また、通信フェーズ中、スライディングウィンドウ機構により、受信可能なウィンドウサイズは動的に変化する。これをフロー制御と呼ぶ。
さらに輻輳を回避するため、ホストは輻輳ウィンドウと呼ばれる変数を管理している。最小値は 1 x MSS 、最大値はウィンドウサイズの最大値である。
ホストは輻輳を回避するように輻輳ウィンドウの値を調整する (輻輳制御)。
実際に送信されるバイト数は、服装ウィンドウの値と、通知された受信可能ウィンドウサイズの値を比較し、小さい方が採用される形となる。

スロースタートアルゴリズム

ホスト同士が同じ LAN に存在せず、途中経路にルータや低速な回線が存在しているとき、ウィンドウサイズの最大値で通信すると、通信能力の限界を超えて輻輳が発生する可能性がある。
そこで輻輳を生じさせずに十分な電送効率が得られる適切なウィンドウサイズを探し出すため、スロースタートアルゴリズムが用いられる。

通信フェーズ開始時、輻輳ウィンドウを 1 x MSS から開始する。その後、確認応答パケットを受信した個数だけ、輻輳ウィンドウを MSS ずつ増やしていく。
最初は輻輳ウィンドウ: 1 、送信パケット: 1 個であり、確認応答パケット: 1 個を受信すると、輻輳ウィンドウ: 2 に更新される。
次に、輻輳ウィンドウ: 2 、送信パケット: 2 個となる。確認応答パケット: 2 個を受信すると、輻輳ウィンドウ: 4 に更新される。
輻輳ウィンドウは 8, 16, 32 というように指数関数的に増加する。

輻輳回避アルゴリズム

重複 ACK (3 回以上連続した同じ ACK) を受け取ると、輻輳が発生したと判断し、ウィンドウサイズを一旦半分に縮小してから、輻輳ウィンドウを徐々に (直線的に) 増やしていく (輻輳回避アルゴリズム) 。
この仕組みにより、輻輳がすぐに再発しないようにしている。
一方、再送タイムアウトが発生した場合は、スロースタートからやり直し、再送タイムアウトが発生した時点のウィンドウサイズの半分に到達してからは輻輳回避フェーズに入る。

参考

TCP 接続リセット

コネクション確立フェーズまたは通信フェーズで、受信した TCP セグメントのヘッダに解決不能のパラメタが存在している場合、TCP 接続がリセットされる。
代表例は、コネクション確立フェーズにおいて、最初の確立要求パケットの宛先ポート番号が宛先ホスト上で実行されているアプリケーションで対応していない場合である。
このとき、RST / ACK フラグをセットしたパケットが返信される。

f:id:shiro_kochi:2018××××××××:plain:w100:left

TCP 通信のスループット

TCP 通信の実効転送速度は次の指揮で決まる。ここで Round Trip Time (RTT) とはパケットの往復時間のことである。

実効転送速度 = Window Size / Round Trip Time

ホスト A は、送信したいデータ量がウィンドウサイズ以下であれば、確認応答を待たずにデータを連続転送できる。しかし、送信したいデータ量がウィンドウサイズを超えている場合、ウィンドウサイズの分まで連続転送した後は、ホスト B から最初のパケットへの確認応答を受信するまで、後続するパケットを転送できない。
このように、RTT に送信できるデータ量の上限値は、ウィンドウサイズとなる。
通信フェーズの開始直後は、スロースタートアルゴリズムが作用し、ウィンドウサイズは小さい。例えば Web 通信のように数往復でファイルの取得を終えてしまう通信の場合、RTT が大きいと通信回線の帯域を十分に使いきれないことがある。
現在、この問題を改良するための方式がいくつか提唱されており、一部対応 OS が存在する。


 © 2023, Dealing with Ambiguity