Understanding TCP Flags and Header Options

TCP Flag Bits

TCP uses several control flag bits in its header to manage how a connection is established, how data is transferred, and how a connection is closed. Let’s go through each flag one by one.


SYN (Synchronize)

TCP uses the SYN flag bit to establish a connection. When an application asks TCP to open a connection, TCP will send a segment with the SYN bit set to check if the other side is willing to communicate. When the other side receives this SYN, it will respond with SYN+ACK if it is ready. Finally, the sender sends back an ACK to complete the three-way handshake.


ACK (Acknowledgment)

Whenever a device receives a segment with data, or special control flags like SYN or FIN, it must acknowledge it by sending a segment with the ACK flag set to 1. A pure acknowledgment segment (which only carries an ACK) does not itself trigger another ACK in response.


FIN (Finish)

The FIN flag bit is used to close the connection. When the user or application ends the session, TCP will send a segment with FIN=1. The other side usually responds with an ACK first, and then later sends its own FIN when it is ready to close. The original side then replies with a final ACK. This process is known as a four-way termination.
In some cases, if the other side has no more data, it can send FIN+ACK together and the closing looks similar to the three-step process of connection establishment.


PSH (Push)

The PSH flag bit tells the receiver to immediately deliver the received data to the upper layer, instead of waiting for the buffer to fill. This is useful in interactive applications such as Telnet, SSH, or FTP control connections, where data needs to reach the application right away without delay.


URG (Urgent)

The URG flag bit marks certain data in the TCP stream as urgent. Unlike PSH, which pushes all buffered data to the application, URG highlights a specific part of the data that should be given priority. The number of urgent bytes is indicated by the Urgent Pointer field in the TCP header. This allows the receiver to know which part of the stream must be delivered to the application immediately.


RST (Reset)

The RST flag is used when TCP wants to immediately close a connection or reject a request.

For example, if a device receives a segment for a port that is not open, it will reply with an RST. In the same way, if there is a problem in an active connection and one side wants to forcefully end it without waiting for the normal FIN process, it can send an RST to reset the connection right away.


CWR (Congestion Window Reduced)

The CWR flag bit is used in Explicit Congestion Notification (ECN). When the sender receives an ECE signal from the receiver, it reduces its congestion window. To confirm that it has reacted, the sender sets the CWR flag in the next segment. This informs the peer that congestion control measures have been applied.


ECE (ECN Echo)

The ECE flag bit is also part of ECN. When a router along the path marks an IP packet with CE = 11 (Congestion Experienced), the receiving device will set the ECE flag in its ACKs to inform the sender. Once the sender gets this signal, it reduces its sending rate and then sets the CWR flag to acknowledge that it has done so.


TCP Header Options Field

TCP header can be minimum 20 bytes and maximum 60 bytes. That means there is up to 40 bytes available to carry some extra information. Let’s look at some of the common options used in TCP header.


MSS (Maximum Segment Size)

MSS defines the maximum data that TCP can carry in one segment. This depends on the MTU of the Layer 2 technology used.

For example, if we use Ethernet with default MTU of 1500, the MSS will be 1460. This is by considering 20 bytes for IP header and 20 bytes for TCP header. MSS value is exchanged during the 3-way handshake.

Also note that if extra TCP options are added (like timestamp), they also take space in the TCP header. In that case the MSS value will be a bit less than 1460.


Selective Acknowledgment (SACK)

TCP normally gives acknowledgment in a cumulative way. It doesn’t have to send ACK for every segment separately.

For example, if 10 segments of 1000 bytes each are sent, with sequence numbers 1, 1001, 2001 and so on, if all are received properly the receiver will send an ACK number 10001. That means it has received up to 10000.

Now if one segment is lost, say segment 2 (seq number 1001), then the receiver will keep sending ACK 1001. The sender will understand that segment 2 is missing and will retransmit it.

The problem comes when more than one segment is lost. With normal cumulative ACK, the receiver can only point to the first missing segment. The sender has to figure out the rest slowly, which delays retransmission. With SACK, if both sides support it, the receiver can use the TCP options field to carry multiple acknowledgment numbers. These numbers show the ranges of data it is still expecting from the other side. This way, the sender knows exactly which segments were lost and can retransmit only those, instead of guessing or waiting for repeated ACKs.

Illustration of TCP Selective Acknowledgment. PC1 sends five segments with sequence numbers 1, 1001, 2001, 3001, and 4001 to PC2. Segments 2 (1001) and 4 (3001) are lost. PC2 responds with a TCP header where the options field lists acknowledgment numbers 1001 and 3001, indicating the missing segments that need retransmission
Selective Acknowledgment example – PC2 informs PC1 about missing segments (1001 and 3001) using the TCP options field

Window Scaling

The TCP window size field is 16 bits, so the maximum value is 65,535 bytes. This was enough in the early days, but with today’s high-speed links it is very small.

To fix this, TCP uses window scaling. Here the value in the window size field is not the actual buffer size. Instead it has to be multiplied by a scaling factor. This factor is exchanged during the connection establishment and it will be a power of 2.

For example, if the scale factor is 256 and the window size field shows 10,000, the actual buffer size is:

10,000 × 256 = 2,560,000 bytes.

This way TCP can handle much larger window sizes than what can be represented in the 16-bit field.



We’d love to hear your feedback and suggestions about this article. Feel free to reach out to us using the WhatsApp number below.

Sajith Achipra has been a trainer and testing consultant at Zframez Technologies since 2009. With 15+ years of experience, he specializes in networking, Python, development, and testing. He conducts online courses to help students and professionals enhance their skills. You can reach him on WhatsApp at +91 8884 884 844 for your training and testing requirements.