The labs on this site need JavaScript to run. The same content is written out below.
Learn › Networking › The big picture
Layers and encapsulation
You send 1500 bytes, so why do 1616 bytes cross the wire?
A network divides its work into layers. On the sending side, data moves down from the upper layers to the lower layers, and each layer adds a header in front of the data that holds the information that layer needs for its own job. This is called encapsulation. The receiving side removes the headers one at a time in the reverse order.
Partly checked against real execution · The number of pieces and their sizes for 10 combinations were checked on Node.js 24 by building the real header bytes, attaching them, and unpacking them. The header sizes and the correspondence between layers are explanations based on RFC 9293, 791, 894, and 1122
Concepts in this lab
- OSI model
- A model that divides the process of network communication into seven layers by role. From the bottom, they are the physical, data link, network (IP), transport (TCP/UDP), session, presentation, and application (HTTP) layers. Each layer does its own job by using the functions of the layer directly below it. It is the reference for calling the location of a device or a problem "Layer N".
- TCP/IP model
- A model that divides the protocols the internet actually uses into four layers by role. From the top, they are the application layer (HTTP, DNS), the transport layer (TCP, UDP), the internet layer (IP), and the link layer (Ethernet, Wi-Fi). Compared with the OSI model, the application, presentation, and session layers are combined into the one application layer, and the data link and physical layers are combined into the one link layer. Each layer leaves delivery to the layer directly below it and does only its own job, so if the technology of one layer changes, the other layers can be used as they are.
- Encapsulation and decapsulation
- Encapsulation is the process, on the sending side, of adding the header of a layer in front of the data every time the data moves down to a lower layer. An HTTP message gets a TCP header, an IP header, and an Ethernet header in that order, and each layer treats what it received from above as content and does not look inside it. Decapsulation is the reverse on the receiving side: the headers are checked and removed in the opposite order as the data moves up to the upper layers. The name is the same as encapsulation in object-oriented programming, but it is a different concept.
- Segment, packet, and frame
- These are the names that the same data is given at each layer. Application data with a TCP header added is called a segment, a segment with an IP header added is called a packet (an IP datagram), and a packet with an Ethernet header and a frame check sequence at the end added is called a frame. The TCP header contains a port number that identifies a program, the IP header contains an IP address that identifies a computer, and the Ethernet header contains a MAC address that identifies a device on the same network. In everyday speech, people often call all of them packets without distinguishing the layer.
- MTU and MSS
- The MTU is the largest IP packet that the link layer can carry in one frame, and on Ethernet it is 1500 bytes. The MSS is the largest amount of data that fits in one TCP segment, which is the MTU minus the IP header and the TCP header. When both headers are the default 20 bytes, the MSS on Ethernet is 1460 bytes. If the data to send is larger than the MSS, TCP splits it into several pieces, and TCP on the receiving side joins them again using the sequence numbers.
Try these
- Default settings — 1500 bytes with an MTU of 1500. Even though the size equals the MTU, the message becomes two pieces.
- Exactly one piece — 1460 bytes become exactly 1500 bytes once the headers are added.
- Short request — 300 bytes. It is not split; only the headers are added.
- Long data — 10000 bytes is split into 7 pieces, and each piece gets its own headers.
- A smaller MTU — The same 1460 bytes now become two pieces.
Running with the default settings
- Application layer (HTTP): The browser creates the HTTP message to send to the server. Its size is 1500 bytes. This layer only decides "what content is exchanged" and leaves how it reaches the other side to the layers below.
- Transport layer (TCP): First, work out how much can be sent at one time. The MTU, the largest size the link layer carries in one frame, is 1500 bytes, and the 20-byte IP header and the 20-byte TCP header must fit inside it, so one piece can carry up to 1460 bytes of data (the MSS). The 1500 bytes of data to send are larger than that, so the data is split into 2 pieces (1460, 40 bytes).
- Transport layer (TCP): The first piece gets a 20-byte TCP header in front. Wrapping the data with a header like this is encapsulation. The header holds the port numbers that identify the sending program and the receiving program (51000 → 80) and a sequence number that tells which byte of the whole data this piece starts at. Data wrapped like this is called a segment. It is now 1480 bytes.
- Internet layer (IP): A 20-byte IP header is placed in front of the segment. The header holds the IP addresses of the sending computer and the receiving computer (192.168.0.10 → 192.168.0.20). Data wrapped like this is called a packet. It is now 1500 bytes. This fills the MTU of 1500 bytes exactly.
- Link layer (Ethernet): A 14-byte Ethernet header is placed in front of the packet, and a 4-byte frame check sequence (FCS) for error checking is placed after it. The header holds the MAC addresses of the two devices that exchange this data within the same network (00:00:5e:00:53:0a → 00:00:5e:00:53:14). Data wrapped like this is called a frame. 1518 bytes go out on the wire.
- The remaining pieces are wrapped in the same order. The headers are added to each piece separately. With 2 frames and 58 bytes added to each, 116 bytes were added in all. Counting the 1500 bytes of data, 1616 bytes went out on the wire.
- Receiving side, link layer: It takes in the frame and checks that the destination MAC address is its own and that the check value in the FCS is correct. If both are fine, it removes the Ethernet header and the FCS and passes the packet inside up to the next layer. What was added last when sending is removed first.
- Receiving side, internet layer: It checks that the destination IP address in the IP header (192.168.0.20) is its own. If it is, it removes the IP header and passes the segment inside up to TCP.
- Receiving side, transport layer: It looks at the destination port 80 in the TCP header to decide which program (the web server) the data is for. It uses the sequence numbers to join the 2 pieces in order and then removes the header.
- Receiving side, application layer: The web server receives the original HTTP message of 1500 bytes exactly as it was. It does not know how many pieces the message was split into on the way, or which headers were added and removed.
Result of this run
- The MTU is a limit on the size of the packet, which includes the IP header and the TCP header, not on the size of the data. So one piece carries only up to 1460 bytes of data (the MSS), which is the MTU minus 40 bytes. This is why data that is equal to the MTU, or slightly smaller, still becomes two pieces.
- Each layer looks at a different address. The transport layer uses a port number to identify a program, the internet layer uses an IP address to identify a computer, and the link layer uses a MAC address to identify the next device on the same network. Each layer reads only its own header and treats everything inside it as content, so you can change the technology of one layer (wired to wireless, or HTTP to another protocol) and keep using the other layers as they are.
Code
// Node.js. Build each header as a chunk of bytes of that size and attach them in order (the content is left empty; only the sizes matter).
const mtu = 1500;
const message = Buffer.alloc(1500); // HTTP message (application layer)
const tcpHeader = Buffer.alloc(20); // port numbers, sequence number, and so on
const ipHeader = Buffer.alloc(20); // IP addresses, and so on
const ethHeader = Buffer.alloc(14); // MAC addresses, and so on
const fcs = Buffer.alloc(4); // frame check sequence (at the end of the frame)
const mss = mtu - ipHeader.length - tcpHeader.length; // data that fits in one piece
let total = 0;
for (let at = 0; at < message.length; at += mss) {
const data = message.subarray(at, at + mss); // one piece
const segment = Buffer.concat([tcpHeader, data]); // transport layer: segment
const packet = Buffer.concat([ipHeader, segment]); // internet layer: packet
const frame = Buffer.concat([ethHeader, packet, fcs]); // link layer: frame
console.log(data.length, segment.length, packet.length, frame.length);
total += frame.length;
}
console.log(total); // total size that went out on the wire
Assumptions of this model
The header sizes are the default sizes without options. The 20-byte TCP header follows RFC 9293 section 3.1, the 20-byte IPv4 header follows RFC 791 section 3.1, the 14-byte Ethernet header (destination MAC 6 + source MAC 6 + type 2) and the 4-byte FCS follow IEEE 802.3, the Ethernet MTU of 1500 bytes follows RFC 894, and the rule that the MSS is the MTU minus 40 bytes follows RFC 9293 section 3.7.1. The four layers of TCP/IP and the names segment, packet (IP datagram), and frame are in RFC 1122 sections 1.1.3 and 1.3.3. The correspondence with the seven OSI layers is not set by a standard; it is a pairing widely used in textbooks. What was checked by execution is the calculation: for each of 10 combinations, on Node.js 24, the text of a real HTTP request was built, the TCP, IPv4, and Ethernet headers and the check value were built as bytes in the positions the standards specify and attached, and the number of pieces and their sizes were measured and checked against the model. The frames were also unpacked and joined again to confirm that the result equals the original message, and the same message was sent over a TCP connection on 127.0.0.1 to confirm that the receiving program gets the same bytes. The frames that the operating system actually puts on the wire were not captured and inspected. In practice, the two sides tell each other their MSS when the connection is set up; when TCP options (such as a 12-byte timestamp) are present, the data in one piece shrinks by that amount; and in settings where the network card does the splitting instead, packet capture tools may show the large block from before the split. Packet capture tools usually show frames without the FCS, so the largest frame appears as 1514 bytes. The 8 bytes of synchronization signal before a frame and the gaps between frames are not counted. A piece with fewer than 6 bytes of data would get extra padding bytes to reach the Ethernet minimum frame size, and only sizes that do not produce such a piece were chosen. The two computers are assumed to be on the same network. If they were on different networks, the destination MAC address would be that of the default gateway, and at each router only the Ethernet header would be replaced. With HTTPS, the HTTP message is encrypted with TLS before TCP carries it. Port 51000 and the addresses in the MAC address range 00-00-5E-00-53-xx reserved for documentation (RFC 7042, now RFC 9542) are examples.
Previous lab: From URL to response · Next lab: URL structure