Engineering Atlas › Foundations

Networking Basics: IP, TCP, UDP and DNS

15 min read · last reviewed 2026-10-17

Open in the interactive app: practice, quiz, mock interview →

In one minute

How it works

Layers: each one solves one problem

Networking is built in layers. The link layer (Ethernet, Wi-Fi) moves frames between machines on the same local network, identified by MAC addresses. The network layer (IP) moves packets between networks, hop by hop through routers. The transport layer (TCP, UDP) moves data between programs, identified by port numbers. The application layer (HTTP, DNS, SMTP, gRPC) defines what the bytes mean. Each layer wraps the data in its own header, like envelopes inside envelopes, and the receiver unwraps them in reverse.

IP: addresses and best-effort delivery

An IPv4 address is 32 bits, written as four numbers such as 203.0.113.7. There are only about 4.3 billion of them, so most devices sit on private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) behind a router doing network address translation (NAT), which rewrites addresses and ports as packets leave and return. IPv6 uses 128-bit addresses and removes the shortage.

The /8 in 10.0.0.0/8 is a prefix length: the first 8 bits name the network and the rest name hosts in it. Routers forward packets by looking up the longest matching prefix in their routing table and sending the packet to the next hop. No router knows the full path; each makes one local decision. Every packet carries a TTL counter that each router decrements, so a packet stuck in a routing loop is eventually dropped.

IP promises nothing beyond trying. A router with a full queue drops packets, and two packets can take different paths and arrive out of order.

Ports and sockets

An IP address finds a machine; a port finds a program on it. A server listens on a well-known port (443 for HTTPS, 53 for DNS, 5432 for Postgres). The client's OS picks a temporary ephemeral port for its side. A TCP connection is identified by four values: source IP, source port, destination IP and destination port. In code you never see packets; you see a socket, a file descriptor you can read and write.

TCP: a reliable stream over an unreliable network

TCP numbers every byte. The receiver sends back acknowledgements (ACKs) saying "I have everything up to byte N". If the sender gets no ACK within a timeout, it sends the data again. The receiver uses sequence numbers to put out-of-order segments back in order and to throw away duplicates. Your program sees a clean stream of bytes, in order, with no gaps.

Before data flows, the two sides do a three-way handshake (High Performance Browser Networking, ch. 2): the client sends SYN, the server replies SYN-ACK, the client sends ACK. This agrees on starting sequence numbers and costs one full round trip. TCP also controls speed: flow control stops a fast sender from overrunning a slow receiver, and congestion control stops senders from overloading the network, starting slowly and speeding up while ACKs keep arriving.

One consequence surprises new engineers: TCP is a stream, not a sequence of messages. Two write calls of 100 bytes can arrive as one read of 200 bytes, or as reads of 37 and 163. Protocols on top of TCP must frame their messages, with a length prefix or a delimiter.

UDP: just send it

UDP sends independent datagrams with an 8-byte header: source port, destination port, length and checksum (RFC 768). No handshake, no retransmission, no ordering. That sounds worse, but it suits cases where late data is useless (voice, video, games) or where the application wants its own reliability rules. DNS queries usually travel over UDP because one small question and one small answer do not need a connection. QUIC, the transport under HTTP/3, runs over UDP and implements its own reliability and encryption in user space.

DNS: the internet's phone book, with caches

When your code connects to api.example.com, the OS first checks /etc/hosts and its local cache, then asks a recursive resolver (your company's, your ISP's, or a public one such as 1.1.1.1). If the resolver has no cached answer, it asks a root server, which points to the .com servers, which point to the authoritative servers for example.com, which return the record. Common record types are A (IPv4 address), AAAA (IPv6 address), CNAME (an alias for another name), MX (mail server) and NS (which servers are authoritative). Each answer carries a TTL in seconds, and every resolver along the way may cache it that long; a TTL of 0 means use it only for the current transaction (RFC 1035).

Down the stack

Layer 1The contract

IP promises best-effort delivery of individual packets, with no promise of arrival, order or uniqueness. TCP promises that bytes are delivered to the receiving application exactly once and in order, or the connection fails with an error; it does not promise when, and it says nothing about whether the remote application processed the data. UDP promises only that a datagram, if delivered, is intact (when the checksum is used). DNS promises an answer that was correct at some point within the record's TTL, not the current truth.

Layer 2The mechanism

A TCP segment header is at least 20 bytes (RFC 9293) and carries source and destination ports, a 32-bit sequence number, a 32-bit acknowledgement number, flags (SYN, ACK, FIN, RST, PSH), and a 16-bit receive window that tells the sender how much buffer space is free. Connections move through states such as LISTEN, SYN_SENT, ESTABLISHED, CLOSE_WAIT and TIME_WAIT. The side that closes first waits in TIME_WAIT so late packets from the old connection cannot be mistaken for a new one. The spec sets that wait to twice the maximum segment lifetime, and takes the lifetime as 2 minutes, so 4 minutes (RFC 9293); Linux hard-codes a shorter 60 seconds.

Retransmission uses a timeout computed from measured round-trip time (RFC 6298), plus fast retransmit: three duplicate ACKs for the same byte suggest a single lost segment, which is resent without waiting. Congestion control keeps a congestion window. Modern stacks start at 10 segments, at most 14,600 bytes (RFC 6928), double it each round trip in slow start, and cut it back on loss. Linux distributions usually ship CUBIC, but the default is a kernel build setting and reno is always available (kernel docs); BBR is an alternative that models bandwidth and delay.

A DNS message has a 12-byte header (an ID, flags, and counts of questions and answers) followed by questions and resource records. Classic DNS over UDP limits responses to 512 bytes and sets the truncated (TC) flag when an answer does not fit (RFC 1035). The EDNS(0) extension allows larger ones, but big UDP answers get fragmented and fragments are unreliable and easier to spoof, so the 2020 DNS flag day settled on a default buffer of 1,232 bytes (the IPv6 minimum MTU of 1,280 less 48 bytes of headers) and a retry over TCP beyond that (DNS Flag Day 2020).

Layer 3The machine

A standard Ethernet frame carries at most 1,500 bytes of payload (the MTU). Subtract 20 bytes of IPv4 header and 20 of TCP header and each segment holds at most 1,460 bytes of your data. The network card writes arriving frames into a ring buffer in RAM and signals the kernel, which runs the IP and TCP code and appends the payload to the socket's receive buffer. Your read call copies from that buffer into your program. A write copies into the send buffer and usually returns before anything is on the wire.

Speed of light in fibre is about 200,000 km/s, so 5,000 km one way costs 25 ms and a round trip at least 50 ms before any router or queue delay. Bandwidth can be bought; latency mostly cannot. Linux assigns ephemeral ports from 32768 to 60999 by default (kernel docs), about 28,000 ports, so a client opening short-lived connections to one server at a high rate can run out while old connections sit in TIME_WAIT.

Why it's built this way

  1. Physical links drop and corrupt data, and a network of millions of routers cannot coordinate a global path, so IP does simple local forwarding and promises nothing.
  2. Keeping routers simple pushed reliability to the endpoints, so TCP adds sequence numbers, ACKs and retransmission in the operating systems at each end.
  3. Retransmitting blindly would collapse a congested network, so TCP measures round trips and adapts its sending rate.
  4. Reliability costs round trips and head-of-line blocking (one lost segment holds up everything behind it), so UDP exists for applications that would rather handle loss themselves.
  5. Asking the authoritative servers for every lookup would overload them and add latency, so DNS caches at every level and accepts that answers can be stale for up to the TTL.

Diagram

sequenceDiagram
  participant C as Client app
  participant R as Recursive resolver
  participant A as Authoritative DNS
  participant S as Server
  C->>R: A record for api.example.com? (UDP 53)
  R->>A: query (after root and .com referrals)
  A-->>R: 203.0.113.7, TTL 300
  R-->>C: 203.0.113.7 (cached for 300 s)
  C->>S: SYN seq=x
  S-->>C: SYN-ACK seq=y ack=x+1
  C->>S: ACK, then request bytes
  S-->>C: response bytes, ACKs both ways
  C->>S: FIN
  S-->>C: ACK, FIN

Worked example

A mobile app in Jakarta calls an API hosted in Virginia. The round trip time is about 220 ms. On a cold start the first request pays:

That is about 680 ms before the first byte, of which the server's own work might be 15 ms. A second request on the same connection costs one round trip, 220 ms.

Now the response is 1 MB. With an initial congestion window of 10 segments of 1,460 bytes, the first round trip delivers about 14.6 KB. Slow start doubles the window each round trip: 14.6, 29.2, 58.4, 116.8, 233.6 and 467.2 KB, a running total of about 920 KB after 6 round trips, so the transfer needs 7 round trips, about 1.5 seconds, even on a fast link. The bandwidth is not the limit; the round trips are.

The fixes follow from the arithmetic: keep connections alive and reuse them, serve from a region or CDN edge near the user (a 20 ms round trip makes the same cold start about 70 ms), and send less data. Upgrading the server's network card would change almost nothing.

In the wild

Trade-offs

ChoiceStrengthsWeaknessesChoose when
TCPReliable, ordered, congestion-aware, universalHandshake cost, head-of-line blockingMost request/response and streaming traffic
UDPNo handshake, no head-of-line blocking, tiny headerNo delivery, order or congestion guaranteesReal-time media, games, DNS, custom protocols
QUIC (over UDP)Fast setup, independent streams, built-in TLSMore CPU, some middleboxes block UDPWeb and mobile clients on lossy networks
Long DNS TTL (hours)Fewer lookups, resilient to DNS outagesSlow to move traffic during incidentsStable addresses that rarely change
Short DNS TTL (seconds to a minute)Fast failover and traffic shiftingMore queries, more exposure to resolver issuesLoad-balanced or failover endpoints

Pitfalls in production

Leadership lens

Check yourself

  1. Why does TCP need sequence numbers if IP already delivers packets to the right address?

    Show answer

    IP can drop, duplicate and reorder packets; sequence numbers let the receiver put bytes back in order, discard duplicates and tell the sender what is missing so it can retransmit.

  2. A client sends two 50-byte messages over one TCP connection and the server's first read returns 100 bytes. Is this a bug?

    Show answer

    No. TCP is a byte stream with no message boundaries, so the application must frame messages itself, for example with a length prefix.

  3. You changed a DNS record's IP five minutes ago, but some users still reach the old server. Why?

    Show answer

    Resolvers and clients cached the old answer and may keep it for up to the record's TTL, which was longer than five minutes.

  4. Why would a video call prefer UDP over TCP?

    Show answer

    A lost audio or video packet is useless once its moment has passed; TCP would retransmit it and hold up newer data behind it, while UDP lets the app skip the gap and keep playing.

Sources and further study

Primary

Systems docs

Books

Other curricula

Watch

Free resources

Open in the interactive app: practice, quiz, mock interview →