The Transmission Control Protocol (TCP) defines connections between hosts over the network at the transport layer (L4) and enables communication between applications on separate devices. It was designed to solve common networking problems including unreliable and unordered packet delivery, lost or duplicated packets, and network congestion. For example, TCP specifies that a server acknowledges the packets it receives so the client can retransmit lost packets only if necessary. It also guarantees ordered packet delivery to the receiving application by keeping track of the sequence numbers of sent and received chunks of data.
In terms of efficiency and network congestion, there are a few scenarios that can lead to problems. Clients sending larger segments than a server can handle at any given time can lead to excessive retransmissions. On the other hand, if a server repeatedly advertises a small receive window size (the amount of data it is capable of receiving) because it is processing data from its buffer too slowly, the client will continually send small segments instead of a few larger ones. These frequent small chunks of data are much less efficient due to the size of the TCP headers required for each segment relative to the data they contain.
One of the ways that TCP mitigates some of these problems is through its use of a sliding window protocol. We'll look at this protocol from the perspective of a server as the receiver and a client as the sender.
Sliding Window Protocol: Receiver
Like we mentioned above, the TCP window size (also called the receive window) is the amount of free space in the server's receive buffer. This value is returned to the sender in the TCP header of an acknowledgment and provides a limit to the amount of data the sender can transmit before waiting for another acknowledgement. The receive window size is determined by the server's buffer size, or congestion window, and the amount of data it has received but not yet processed. Besides the window size, the receiver's acknowledgment also contains a field for the next sequence number the server expects to receive, which also informs the client that all bytes prior to that number have been received. Example receive window diagram.
For a simple example, let's say we have a server with an empty receive buffer capable of holding 100 bytes (1). After establishing a connection, a client transmits 40 bytes. The server receives all of them (2), processes 30 bytes (3), and returns an acknowledgement number of 41 and a window size of 90 to the sender.
Next, the client sends 90 bytes. The server receives them (4) and processes another 30 bytes from its buffer (5). The server returns an acknowledgement number of 131 and a window size of 30.
Sliding Window Protocol: Sender
As you might expect, the client has a send window to match the server's receive window. The size of the send window is the total number of bytes that the client is allowed to have unacknowledged at a time. In general, the send window is bounded by the minimum of its send buffer size and the server's receive window size, but it is also affected by network congestion and the number of sent but unacknowledged bytes. The sender also has a usable window, which is a subset of the send window for the unsent bytes the receiver's buffer still has room for. In other words, the usable window is the send window minus any sent bytes that haven't been acknowledged yet. Example send window diagram.
The "sliding" aspect of the protocol is easier to see by looking at a simplified visual example of sender's operation:
An application on a client has 500 bytes that need to be sent to a server (1). The server has 50 bytes already in its 150 byte receive buffer, so it sets a receive window size of 100. After establishing a connection, the client sends 30 bytes out of the 100 byte send window. Since the 30 bytes have not been acknowledged yet, the client still has a usable window of 70 bytes (2).
Let's say the client sends the next 70 bytes before waiting for an acknowledgement (3). This uses up the current usable window since the client has sent the full amount the receiver can handle.
Next, the server acknowledges the first 30 bytes. The sender slides its send window right by 30 and updates its usable window to account for the acknowledged bytes (4). If the server then processes everything in its buffer, it will acknowledge the next 70 bytes and update its receive window to 150 bytes. The client increases its send window and usable window to match and slides them both to the right. The client then transmits another 100 bytes (5).
This process continues until all of the sender's bytes have been transmitted.
In reality, chunks of data called segments, each with a TCP header, are transmitted between a sender and receiver. Additionally, the speed with which the send window slides through the client's buffer varies depending on how quickly the client gets data from the sending application, how quickly the server processes the data in its receive buffer, if any packets are lost in transmission, and the specifics of the sliding window protocol implementation and congestion control algorithms.
TCP is complex but is used extensively by applications that depend on its reliability, so problems like misconfigured settings can have wide-ranging impacts on your network. Visibility into your network and knowledge of how the protocol operates can help minimize troubleshooting time and make problems easier to identify.
If you want to learn more, check out our free online demo and our other TCP-related content.