Why Do You Need the TCP Window Size?

adil
5 min readJul 12, 2022

You most probably know that TCP is reliable, and UDP is an unreliable protocol. Because TCP is a stream-oriented protocol. When a sender transmits some data to a receiver, the receiver will need to send an “acknowledge” to the sender. So, the sender ensures that the data has been delivered to the receiver.

***** You can follow me on LinkedIn *****

Photo by Erik Mclean on Unsplash

Imagine that the receiver sends an acknowledgment for every packet that reaches the receiver. It will impact network speed, and applications should be notified for each packet.

I want to share some of the output of a tcpdump from my computer:

Multiple packages, one acknowledge

According to the tcpdump output, my computer received 12 TCP packages and sent 1 acknowledge message to the remote server. Then, 15 TCP packages were received, and 1 acknowledge message was sent.

How cool!

How does my machine decide to send an acknowledgment packet to the remote server?

Each TCP packet has a header. Each header has a 2-byte long reserved field for Window Size. The receiver and the sender reveal their available Window Size in the TCP package’s header. You can see the Window Size value in the output above: the parameter `win`.

The window size value is variable for each TCP packet. It can be changed in each package.

What is the Window Size?

The receiver tells the sender its window size (how much data to receive before sending an acknowledgment).

When the sender transmits some data to the receiver, the data will be kept in the receiver’s TCP buffer. Until when? Until the receiver application reads the data from the receiver’s TCP buffer.

This feature has two advantages:

1) The application does not need to be notified each time a package arrives. The application receives bulk data from the TCP buffer.

2) If the application is somehow momentarily unavailable (iowait etc.), TCP will buffer some data until the application is ready to read it.

What happens if the window size is full?

When the application does not read data from the TCP buffer, TCP tells the sender, “my window size for this TCP connection is 0 (zero)”.

I wrote a simple TCP server in Node.js. It listens on a TCP port but does not read data from TCP:

const server = new net.Server();
server.listen(8080, "0.0.0.0", function() {
console.log(`Server is ready to use.`);
});

I sent some data to the server. The window size is reduced to 0 at the end:

Because the application isn’t reading the data in the TCP buffer and the receiver “Hey, my buffer for this connection is full!” says.

Please note that the buffer is full specifically for this connection. If I create another connection and send some data, another TCP buffer space will be allocated for the new connection.

What is the maximum value of Window Size?

The Window Size space field is 2-byte long in the TCP header. This means that the maximum window size (read buffer) value can be 65,535 bytes. We use the TCP Window Scale Factor, as 65,635 bytes are pretty low for modern network infrastructures.

RFC 1323 defines the Window Scaling option to expand the maximum buffer per connection. Thanks to the Window Scaling Factor option, the maximum window size can be increased from 65,535 bytes to 1 Gigabyte.

The window scaling (wscale parameter in tcpdump) option is specified during 3-way TCP handshake. The receiver tells the available buffer space for the connection. The window scaling option is an additional parameter to the window size.

The formula is to calculate the available window size per TCP connection:

(2 ^ window scale factor value) * window size.

According to RFC 1323, the window scale factor’s maximum value can be 14

An example calculation:

Window size = 65,535
Window scale factor = 14
(2 ^ 14) * 65, 535
16384 * 65,635 = 1 Gigabyte

If the window size is 65,535 bytes and the window scale factor is 14, TCP can send an acknowledge after 1 Gigabyte of data is transferred.

Please note that it is not required! The TCP may send an acknowledgment after (say) 1000 bytes of data is transferred.

How to calculate TCP Throughput?

TCP Throughput means the maximum number of bits that can be transmitted per second.

TCP Throughput formula is pretty simple:

Window size in bit per second / RTT in seconds (Round Trip Time)

An example calculation:

Window size: 65535 bytes
Window scale factor: 7
RTT: 35 ms (0.035 seconds)
Total window size per connection: (2 ^ 7) * 65535 = 8388480 Bytes8388480 * 8 = 67107840 (Window size in bit)67107840 / 0.035 = 1917366857 bits = 1917 Mbps

So you need to decrease RTT or increase the Window size to increase TCP Throughput.

How to calculate the most efficient TCP Window?

(Bandwidth in bit per second * RTT in seconds) / 8 = Window Size / 1000

An example calculation

Bandwith: 100 Mbps -> 100.000.000 Bits
RTT: 65 ms -> 0.065 seconds
(100.000.000 * 0.065) / 8 = 6.500.000
6.500.000 / 8 = 812.500 Bytes
812.500 / 1000 = 812 KB Window Size.

What is the difference between MSS and Window Size?

MSS (maximum segment size) and Window Size things are independent of each other.

MSS specifies the largest amount of data (in bytes) that can be transmitted in a single TCP segment.

The window size specifies how much data can be received before sending an acknowledgment.

How to adjust Window Size in Linux?

It would be best if you made sure window scaling is enabled on your Linux:

sysctl net.ipv4.tcp_window_scaling

After that, you must modify these system variables:

net.core.rmem_max
net.ipv4.tcp_rmem

Here is an output from my Linux server (default settings):

root@main:~# sysctl net.ipv4.tcp_rmem
net.ipv4.tcp_rmem = 4096 131072 6291456

First column -> minimum value of window size
Second column -> default value of window size
Third column -> maximum value of window size

--

--