Where did the other 42 bytes come from?
You call send with the string "hello". Five bytes.
Run tcpdump on the same machine and it reports a 47-byte frame
leaving the network card. The five bytes you wrote are in there. They are the
last five. Everything before them was written by the kernel.
Most networking courses start here with a diagram of seven layers and a paragraph about abstraction. This lesson starts with the bytes instead. Once you have seen the 47 bytes laid out in memory, the layers stop being a diagram and become what they actually are: headers, stacked in front of your data.
A header is a struct prepended to your bytes
Think of the frame as a byte array. Your payload sits at the end. In front of it the kernel places a small fixed-layout struct — a header — that describes the payload to the next machine. In front of that it places another header for a different reader. Three headers, three readers.
| bytes | header | answers | read by |
|---|---|---|---|
| 0–13 | Ethernet (14) | which NIC on this cable? | switch, next hop |
| 14–33 | IPv4 (20) | which machine on the internet? | every router |
| 34–41 | UDP (8) | which program on that machine? | destination kernel |
| 42–46 | payload (5) | whatever you meant | destination program |
Each header has one job: get the bytes to the next reader. The Ethernet header only has to reach the router on your local cable. The IP header has to reach a machine on the other side of the planet. The UDP header has to reach one specific program on that machine. None of them look at your five bytes.
0x0800 means
"the next 20 bytes are an IPv4 header". The IPv4 header has a 1-byte protocol
field: 17 means "the next 8 bytes are UDP" (6 means TCP).
A receiver parses the frame front to back by following these fields. It never guesses.
The headers as C structs
Because a header is a fixed layout of integers, you can describe it as a struct.
These are simplified versions of what the kernel uses. Note the sizes: every field
is exactly as wide as it needs to be, and there is no padding anywhere — the
designers chose offsets that keep every field aligned to its own size, which is
why sizeof comes out to exactly 14, 20, and 8.
Look at src_addr. An IPv4 address is a uint32_t.
The dotted form 192.168.1.7 is just how humans print the four bytes
c0 a8 01 07. A port is a uint16_t. These are integers,
and the next two lessons treat them as integers.
0x1F90. On the wire it appears as the bytes 1F 90:
most significant byte first. Your x86 or ARM CPU stores the same uint16_t
in memory as 90 1F. If you cast wire bytes to a uint16_t
and read it directly, you get 0x901F = 36895, not 8080. Lesson 03 covers
the conversion functions. For now, remember: the wire has one byte order, your CPU
may have another.
Watch the frame grow
Step through the visualization below. It starts with the five bytes you wrote and
prepends one header at a time, exactly as the kernel does on the way down to the
network card. Each row is 16 bytes, the way tcpdump -xx and
hexdump print them. Hover any byte to see which header it belongs to.
The frame grows in front. Your payload never moves. This is why the kernel allocates packet buffers with headroom before the data: it can prepend each header by moving a pointer backwards instead of copying the payload.
Who reads what
Follow the frame as it leaves your machine. The switch in your house reads bytes 0–13, finds the destination MAC, forwards the frame out the right port, and stops. It never reads byte 14. Your router reads bytes 14–33, finds the destination IP, decrements the TTL, picks the next hop, and — this is the part people miss — replaces the Ethernet header with a new one addressed to the next router. The IP header and everything after it travel untouched.
Twelve routers later the frame reaches the destination machine. Its kernel reads the
IP header, sees protocol 17, reads the UDP header, sees port 8080, finds the program
that owns port 8080, and copies bytes 42–46 into that program's buffer.
Your five bytes arrive. Nothing else does: the program only ever sees
"hello".
The size limit you will hit
Ethernet frames carry at most 1500 bytes after the Ethernet header. This is the MTU (maximum transmission unit). Subtract 20 for IPv4 and 8 for UDP: your payload in a single frame is at most 1472 bytes. Send more and the kernel either splits it into fragments (slow, fragile, often dropped) or refuses. Every protocol you will meet in this track — DNS, QUIC, VPN tunnels — is designed around that 1472-byte budget.
See it yourself
Find 1f90 on the last line: port 8080. Find 4011 on the
middle line: TTL 64, protocol 17. Find 6865 6c6c 6f: your five bytes.
Every number in the visualization above is on this screen. The layers are real, and
they are nothing more than this.
A packet is your bytes with three fixed-layout headers prepended — Ethernet for the next hop, IP for the machine, UDP for the program — and each reader looks only at its own.