Internet 101: TCP

This article assumes the reader has basic knowledge of IP.

IP gives us addressing and the ability to send packets from one machine on the internet to another, assuming that routing is configured correctly at each hop. However, it provides little else.

Imagine trying to send a large file over IP. Due to the length restriction on IP packets, the file is broken up into chunks, and each chunk is sent in order as an IP packet. In this scenario, any number of things can go wrong. An unreliable link may corrupt a packet. A router may choose to route one or more packets differently from the others. Packets may be silently dropped or duplicated in misconfigured networking devices. Eventually, the destination machine receives the packets out of order, with some missing, corrupted or duplicated. Obviously, reliably reconstructing the file from these packets is impossible.

The Transmission Control Protocol solves this problem. It is a transport layer protocol that provides reliable connections between two machines. It is designed to operate on top of a connectionless network layer protocol, such as IP. TCP makes very few assumptions about the underlying protocols and data links. It only assumes that a potentially unreliable service such as IP exists, capable of transmitting data segments. The underlying protocol abstracts away the routing and any required fragmentation or reassembly.

Just like IP, a TCP packet has a header and data section. The header contains a number of fields that allow TCP to function. A subset of these fields:

  • Source and destination ports (16 bits each)
  • Sequence number (32 bits)
  • Acknowledgment number (32 bits)
  • 9 control bits
  • Window size (16 bits)
  • Checksum (16 bits)

The TCP header does not replace the underlying protocol’s header. Instead, the TCP packet is provided as data to the network protocol interface. For example, a TCP packet is encapsulated by an IP header before being transmitted.

Establishing a connection

TCP introduces the concept of a port. Ports provide multiplexing—a way for multiple process running on a machine to establish TCP connections. The destination port allows the kernel to determine which process should receive the data.

In general, one machine listens on a port for incoming connections. When another machine wishes to connect to that port, a three-way handshake occurs to establish the connection. The initiating machine sends a SYN segment to the listener. This segment is simply a TCP packet containing no data, only a header. This header has the SYN control bit set, and the initial sequence number.

The listening machine will respond with a SYN-ACK. This includes the listener’s initial sequence number, and an acknowledgment number. The acknowledgment number will be the initiator’s initial sequence number plus one.

Lastly, the requesting machine will respond with an ACK, including the appropriate acknowledgment number. At this point, a full-duplex connection has been established.

Exchanging data

The sequence and acknowledgment numbers are essential for reliability.

The sequence number is the number of the first data octet in the packet (or the next packet, if there is no data present). The only exception to this rule is when SYN is present, in which case the first data octet is the initial sequence number plus one. After the first SYN, the ACK control bit is always set. The acknowledgment number contains the sequence number that the sender is expecting to receive next, and indicates that the sender has received all octets up to that number.

If a packet is lost, the sender will notice that it has not been acknowledged. Either because it receives packets with the same acknowledgment number as before, or because it doesn’t receive any packets at all. To account for packet loss, TCP utilizes a retransmission timout. Due to the variability of network quality, this timeout is dynamically determined based on measured round trip times. If a packet has not been acked within this timeframe, the packet is retransmitted.

The TCP header also contains a 16 bit checksum, calculated over the header, data and a psuedo header. The psuedo header is constructed from the source and destination IP addresses, transport layer protocol (TCP in this case), and the computed length of the TCP packet. The receiver verifies the checksum and discards the packet if the recomputed checksum does not match. The packet is not acked, and will be retransmitted.

Closing a connection

A connection is closed using four segments (although some may be combined), with each machine terminating independently. The machine closing the TCP connection sends a FIN, signaling it has no more data to send. At this point, it will not send any more data, although it may still receive data. The other machine will ACK the segment, and may or may not continue to send data. Once it is also ready to close, it sends a FIN of its own, which will be acked by the initiating machine. The initiating machine will wait a certain length of time before closing the connection and deleting the associated state. The other machine closes the connection as soon as it receives the last ACK.

The order of the segments above is typical, but not always the case. For example, the two machines may send a FIN simultaneously. TCP handles these kinds of scenarios as expected.

The above is only a short description of a TCP connection, and the mechanisms by which it achieves reliable data transfer over an unreliable, connectionless network protocol. The TCP specification also defines the state associated with a connection, the minimum required functional user interface, and a number of other mechanisms including one that manages the rate at which packets are sent. It’s a complex protocol with lots of subtleties, and the full specification is a worthwhile read.

[1] Transmission Control Protocol. RFC 793, 1981. https://tools.ietf.org/html/rfc793