【図解】TCP window size の仕組み〜MSS(MTU)との違い,calculated window size,unknown factor,受信バッファの設定変更~

TCP window size とは

TCPウィンドウサイズとは、クライアントやサーバ等のホストがTCP接続する際にどのくらいのパケットを受け入れられるかを示す値です。受信バッファとも呼ばれます。

TCPヘッダにある Window フィールドを使って、「自分がどれくらいの Byte 数の通信を受け入れられるか」を相手に示す仕組みになっています。

MSS は 1 パケット当たりのパケットサイズに影響を与えますが、Window Size は ACK 無しにどのくらいの TCP ペイロード(MSS)を受信できるかに影響を与えます。

以下に Window Size と MSS(≒MTU)との違いを示します。

MTU は Ethernet インタフェースの1パケットあたりの最大サイズです。MSS は TCP セグメンテーションによる分割時の最大サイズを意味しますが、これは多くの場合、MTU から計算されます。(ルータに adjust-mss の設定があるとルータによって最適なものに書き換えられる)

※ MTU と MSS の違いについては以下を参照して下さい。

【図解】MTUとMSS, パケット分割の考え方(IPフラグメンテーションとTCPセグメンテーション)
【図解】MTUとMSS, パケット分割の考え方(IPフラグメンテーションとTCPセグメンテーション)
MTUとMSSの違い MTU(Maximum Transmission U...

一方、Window サイズはアプリケーションのプログラミングによってそのサイズが決まります。例えば上図の場合、ファイルサービスを行うアプリケーションがパケット受信のためにどれくらいメモリにバッファを設けるかを基準に、開発者が決めます。

また、この Window サイズはパケット送受信の中で変更することができます。つまりアプリケーションが「もう空き容量が 1460 Byte しか無いよ」というときは Window=1460 にして送信します。受け取った相手は状況を察し、1460 Byte 以上は送らないようにします。このように Window を動的に変化させる仕組みを窓の開け閉めになぞらえ「スライディングウィンドウ」と呼びます。

【図解】TCPのフロー制御と輻輳制御とその違い 〜スライディング ウィンドウ サイズ, スロースタート, AIMD〜
【図解】TCPのフロー制御と輻輳制御とその違い 〜スライディング ウィンドウ サイズ, スロースタート, AIMD〜
TCP のフロー制御の実装 TCP ではデータ(セグメント)を受信したことを A...

Calculated window size とは?

Window サイズは TCP ヘッダフォーマットとして 16 bit 用意されています。

単位は Byte ですので、2の16乗=64 KB 分用意されています。TCP が生まれた1981年においてはこの値はそんなに悪くなかったかもしれませんが、現代の技術レベルにおいては全然足りません。

1988年でその問題が予測されていたようで、この年に RFC 1072 として TCP オプションという形で Window Scale が追加されました。

これは Window サイズを何倍するかを決める値です。TCP syn および TCP syn/ack の際にこのオプションを付けて相手に送ることで、そのTCPコネクション内の通信はその倍数分だけ Window サイズを掛け算します。

例えば TCP syn で Window Scale を 256 にして送信した場合、以降の通信で Window=250 とした場合、相手は 250*256=64,000Byte と解釈します。

この掛け算の結果を、Wireshark では [Calculated window size ] と表示します。以下の例だと、"Window size value" が Window フィールドの値、"Window size scaling factor" が TCP syn 時の Window Scale の値、Calculated window size はそれらの掛け算です。

RFC 7323 にも書かれていますが、Window Scale は 2の14乗が上限です。Window Size が 2の16乗なのでこれと合わせて 2 の 30乗 = 1 GByte までを Window Size として使うことができるようになります。

Window size scaling factor: -1 (unknown) とは?

Window Scale オプションは TCP syn, syn/ack の時にしか使うことができません。なので TCP syn や syn/ack の送受信が終わった後からパケットキャプチャを開始した場合は Window Scale が分からないので、[Window size scaling factor: -1 (unknown) ] と表示します。

Windows での受信バッファ(TCP Window Size)の設定

XP 以前はレジストリの変更により任意にサイズ変更が出来たようですが、Vista 以降は "Receive Window Auto-Tuning" 機能に一任され、利用者によるサイズ変更はできないようです。

以下のMSのブログページによると、

https://blogs.technet.microsoft.com/netgeeks/2018/05/21/a-word-about-autotuninglevel-tcp-receive-auto-tuning-level-explained/

Window サイズの決定については2つの要因があるそうです。

  1. その通信を行うアプリケーション側からの指定(つまりプログラマによって決定)
  2. もしアプリケーション側からの指定が無い場合はインタフェースのリンク速度によって決定

2 については以下のルールになるそうです。

Below 1 megabits per second (Mbps): 8 kilobytes (KB)
1 Mbps to below 100 Mbps: 17 KB
100 Mbps to below 10 gigabits per second (Gbps): 64 KB
10 Gbps or higher: 128 KB

ただし、そこから前述した "Receive Window Auto-Tuning" 機能による調整が入ります。デフォルトでは Tuning-Level は [ normal ] に設定されており、このルールの値よりそれなりに大きな値を取ることが出来ます。

もし「出来る限り大きな値を取れるようにしたい!」というのであれば、Tuning-Level を [ experimental ] に設定します。

netsh interface tcp set global autotuninglevel=experimental

逆に、控えめにしたい場合は [ restricted ] , 非常に控えめにしたい場合は
[ highlyrestricted ] を使います。

netsh interface tcp set global autotuninglevel={restricted | highlyrestricted}

また、常にルール通りの固定値にしたいのであれば [ disabled ] を使います。

netsh interface tcp set global autotuninglevel=disabled

なお、MSのブログでは、これらの設定により Window Scale が以下のようになったことをレポートしています。

  • experimental : Window Scale = 14
  • normal : Window Scale = 8
  • restricted : Window Scale = 4
  • highly restricted : Window Scale = 2
  • disabled : Window Scale オプション無し

Linux での受信バッファ(TCP Window Size)の設定

Linux の TCP Window Size の制御は Kernel Parameter により設定されています。

[root@localhost ~]# sysctl -a | grep rmem
net.core.rmem_default = 212992
net.core.rmem_max = 212992
net.ipv4.tcp_rmem = 4096        87380   6291456
net.ipv4.udp_rmem_min = 4096
[root@localhost ~]#

net.core.rmem_default および net.core.rmem_max が基本的に利用される Window Size です。単位は Byte で、default は初期値、max は最大値を意味します。

ですが実は Linux にも Windows のように Auto-Tuning 機能があり、この機能が無効の場合は上記2つにより決まりますが、有効の場合はこれ以外のパラメータも効いてきます。

Auto-Tuning 有効無効は net.ipv4.tcp_moderate_rcvbuf パラメータで決まります。1が有効でデフォルトは 1 です。

[root@localhost ~]# sysctl -a | grep rcvbuf
net.ipv4.tcp_moderate_rcvbuf = 1

これが有効である場合、前述の net.ipv4.tcp_rmem や udp_rmem の設定が効いてくるわけです。

net.ipv4.tcp_rmem の値は [ min , default , max ] という並びになっています。min は最小値、default は初期値、max は最大値ですが、ややこしいことに初期値 (default) は net.core.rmem_default よりもこちらが優先なのですが、最大値 (max) は net.core.rmem_max が優先されます。

https://linux.die.net/man/7/tcp

シェアする

  • このエントリーをはてなブックマークに追加

フォローする