Section 10 · 8 min read
TCP and sockets
Covers the TCP header, connection setup and teardown, sequence numbers, flow control, congestion control (slow start, congestion avoidance, fast retransmit), timeouts and the socket API call order.
On this page
What TCP provides
TCP gives a reliable, in-order, full-duplex byte stream between two processes. It is connection oriented, uses cumulative acknowledgements, retransmits lost data, controls the sender's rate so the receiver is not overrun (flow control) and so the network is not overloaded (congestion control). UDP, by contrast, sends independent datagrams with only ports and a checksum.
The TCP header
| Field | Bits | Notes |
|---|---|---|
| Source port, destination port | 16 each | Identify the processes |
| Sequence number | 32 | Number of the first data byte in this segment |
| Acknowledgement number | 32 | Next byte expected from the other side (cumulative) |
| Header length (data offset) | 4 | In 4-byte words; 20 to 60 bytes |
| Flags | 6 classic | URG, ACK, PSH, RST, SYN, FIN |
| Receive window | 16 | Bytes the receiver can still accept; max 65535 without scaling |
| Checksum | 16 | Over a pseudo-header, the TCP header and data |
| Urgent pointer | 16 | Used with URG |
| Options | 0 to 40 bytes | MSS, window scale, SACK, timestamps |
Sequence numbers count bytes, not segments. SYN and FIN each consume one sequence number; pure ACKs consume none. The 32-bit space wraps after bytes; at high speeds this happens quickly, which is why the timestamp option exists for protection against wrapped sequence numbers.
Connection management
Three-way handshake
- Client sends SYN with initial sequence number .
- Server replies SYN+ACK with its own ISN and ACK .
- Client sends ACK . Data may ride on this segment.
The client's first data byte has sequence number . Random ISNs protect against old duplicate segments and spoofing.
Teardown
Either side sends FIN; the other ACKs it. Each direction is closed separately, so a normal close uses four segments (FIN, ACK, FIN, ACK), though the middle two can be combined. The side that closes first enters TIME_WAIT for MSL so that a lost final ACK can be resent and old segments die out.
Flow control
The receiver advertises a window rwnd equal to its free buffer space. The sender keeps
If rwnd is 0, the sender stops and periodically sends a one-byte probe so that it learns when the window reopens. With a window of bytes and round trip time RTT, throughput is at most , no matter how fast the link is. The window scale option multiplies the 16-bit field by (up to ) for high bandwidth-delay paths.
Retransmission timeout
TCP estimates RTT with exponentially weighted moving averages:
Karn's rule: do not take RTT samples from retransmitted segments, because the ACK could belong to either copy. After a timeout, RTO is doubled (exponential backoff) until a fresh ACK arrives.
Congestion control
The sender keeps a congestion window cwnd and a threshold ssthresh. Its effective window is . GATE questions usually measure cwnd in MSS and assume a full window is sent and acknowledged every RTT.
Slow start
Start with cwnd MSS (newer stacks use larger initial windows, but follow the question). For every ACK, add 1 MSS, which doubles cwnd every RTT. Slow start continues until cwnd reaches ssthresh. Many GATE questions say that cwnd is capped at ssthresh when doubling would overshoot it; follow whatever the question states.
Congestion avoidance
Once cwnd ssthresh, add about 1 MSS per RTT (each ACK adds MSS MSS / cwnd). This is the additive increase part of AIMD.
Reaction to loss
| Event | TCP Tahoe | TCP Reno |
|---|---|---|
| Timeout | ssthresh cwnd/2, cwnd , slow start | Same as Tahoe |
| 3 duplicate ACKs | ssthresh cwnd/2, cwnd , slow start (after fast retransmit) | Fast retransmit; ssthresh cwnd/2; cwnd ssthresh ; fast recovery, then cwnd ssthresh and congestion avoidance |
Fast retransmit: three duplicate ACKs for the same byte mean a segment is missing but later ones are arriving, so the sender resends the missing segment without waiting for the timer.
The resulting cwnd plot for Reno is a sawtooth: linear growth, halve on triple duplicate ACKs, linear growth again. For Tahoe or after a timeout, it drops to 1 and climbs exponentially again.
The socket API
Sockets are the interface between applications and the transport layer.
| Server (TCP) | Client (TCP) |
|---|---|
| socket() | socket() |
| bind() to a well-known port | (bind optional) |
| listen() | |
| accept() blocks | connect() starts the handshake |
| read()/write() or recv()/send() | write()/read() |
| close() | close() |
accept() returns a new connected socket for each client; the listening socket stays open for further connections. connect() performs the three-way handshake. For UDP there is no listen, accept or connect requirement: the server calls socket and bind, then recvfrom and sendto; the client calls socket then sendto and recvfrom.
Worked examples
Worked example 1: Sequence and acknowledgement numbers
Client ISN 500, server ISN 9000. After the handshake the client sends 200 bytes, then 300 bytes. The server replies with 100 bytes after receiving both.
- SYN: seq 500. SYN+ACK: seq 9000, ack 501. ACK: seq 501, ack 9001.
- Data 1: seq 501 (bytes 501 to 700). Data 2: seq 701 (bytes 701 to 1000).
- Server reply: seq 9001, ack 1001. Client's ACK of that: ack 9101.
Worked example 2: Window-limited throughput
rwnd KB (32768 bytes), RTT ms, link 1 Gbps. Throughput Mbps, about half a percent of the link. To fill the link you need MB of window, which requires window scaling.
Worked example 3: cwnd evolution with a timeout
cwnd starts at 1 MSS, ssthresh MSS. Assume doubling is capped at ssthresh. A timeout happens in the round where cwnd .
| Round | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| cwnd | 1 | 2 | 4 | 8 | 16 | 17 | 18 | 19 | 20 | 1 | 2 | 4 | 8 | 10 | 11 |
Timeout in round 9: ssthresh , cwnd . Slow start until 10 (8 doubles to 16, capped at 10), then linear.
Worked example 4: Triple duplicate ACKs in Reno
cwnd MSS in congestion avoidance when three duplicate ACKs arrive. Reno sets ssthresh , resends the missing segment, and after fast recovery continues at cwnd , growing by 1 per RTT: 12, 13, 14, .... Tahoe would instead set cwnd to 1 and slow start up to 12.
Worked example 5: RTO calculation
EstRTT ms, DevRTT ms. A sample of 120 ms arrives.
DevRTT ms (using the old EstRTT, as the RFC does).
EstRTT ms.
RTO ms.
Common traps
- Forgetting that SYN and FIN consume one sequence number each.
- Treating the ACK number as "last byte received". It is the next byte expected.
- Doubling past ssthresh when the question says to cap, or capping when it says not to.
- Halving ssthresh from the old ssthresh instead of from the current cwnd.
- Using the same reaction for timeout and triple duplicate ACKs in Reno.
- Ignoring rwnd: the sender's window is .
- Counting rounds off by one. Decide whether round 1 is cwnd and stick to it.
- Mixing the server and client socket sequences: only the server calls listen and accept.
Quick revision
- Header 20 to 60 bytes; 32-bit seq and ack; 16-bit window; checksum over pseudo-header + segment.
- Handshake: SYN (), SYN+ACK (, ack ), ACK (). First data byte .
- Close: FIN and ACK per direction; TIME_WAIT lasts 2 MSL.
- Flow control: window ; throughput .
- Slow start doubles per RTT; congestion avoidance adds 1 MSS per RTT.
- Timeout: ssthresh cwnd/2, cwnd .
- Reno on 3 dup ACKs: ssthresh cwnd/2, cwnd ssthresh, fast recovery.
- EstRTT with , DevRTT with , RTO EstRTT DevRTT; double RTO on timeout.
- Server: socket, bind, listen, accept. Client: socket, connect.