Thuta Learning
BasicDevOps & Toolsbeginner

The OSI and TCP/IP Models

What you'll walk away with

  • Explain the core ideas behind The OSI and TCP/IP Models
  • Read the diagram and trace how data actually moves through it
  • Run the sample code and verify its output

Build the mental model

Layering exists because a network stack is far too large to design, build, or replace as one piece. If the code that puts bits on a wire were tangled with the code that formats an HTTP request, then switching from Wi-Fi to Ethernet would mean rewriting your web browser. Layering draws the lines deliberately: each layer offers one narrow service upward and depends on one narrow service below. So Wi-Fi can be reinvented without HTTP noticing, and HTTP/3 can appear without touching a single cable.

The OSI model names seven such layers — physical, data link, network, transport, session, presentation, application — and is best treated as vocabulary, not a blueprint. Nobody ships an OSI stack. The TCP/IP model, which real systems actually implement, uses four: link, internet, transport, application. The mapping is loose but useful. OSI's physical and data link collapse into TCP/IP's link; network becomes internet; transport stays transport; and OSI's top three fold into a single application layer — which is why people say "Layer 7" for anything above transport.

The mechanism that makes layering real is encapsulation. As data travels down the stack, each layer prepends its own header and treats what it received as an opaque payload. Your bytes become a segment, the segment becomes a packet, the packet becomes a frame. On the receiving side each layer strips exactly its own header and hands the rest upward, so peers at each level act as if talking directly. That is why a router can forward your traffic while being indifferent to whether it carries HTTP, video, or a game — and why adding encryption at one layer changes nothing elsewhere.

text
OSI VS TCP/IP, AND WHAT ENCAPSULATION LOOKS LIKE
------------------------------------------------
   OSI (7 layers)                 TCP/IP (4 layers)
 +------------------+           +--------------------+
 | 7 Application    |           |                    |
 | 6 Presentation   |---------->|    Application     |
 | 5 Session        |           |                    |
 +------------------+           +--------------------+
 | 4 Transport      |---------->|    Transport       |
 +------------------+           +--------------------+
 | 3 Network        |---------->|    Internet        |
 +------------------+           +--------------------+
 | 2 Data Link      |           |                    |
 | 1 Physical       |---------->|    Link            |
 +------------------+           +--------------------+

Going DOWN the stack, each layer wraps whatever it was handed:

  L7        [ data ]                        your bytes
  L4    [ TCP | data ]                      = segment
  L3  [ IP | TCP | data ]                   = packet
  L2 [ETH| IP | TCP | data |FCS]            = frame
     \____________________________/
        this is what the cable carries

Going UP, each layer removes exactly its own header and no more.

Connect it to a real scenario

Suppose you are debugging why a request never arrives, and you have a packet capture open. Layering tells you exactly where to look, and in what order. Expand one captured frame and you will see the same nesting the model describes: an Ethernet header with two MAC addresses, inside it an IP header with two IP addresses, inside that a TCP header with two port numbers, and only then your HTTP request text.

Read it as a checklist. If there is no frame at all, the problem is below the network layer — cable, Wi-Fi association, switch port. If frames appear but the IP header shows a destination you did not expect, your routing or DNS resolution is wrong, not your application code. If IP looks right but TCP shows repeated SYNs with no reply, something is dropping the connection attempt — a firewall, or a service that is not listening — and reading the HTTP payload would be pointless because there is no HTTP yet.

Encapsulation also explains a very real performance concern: every layer adds header bytes. A tiny 5-byte message ends up inside a 36-byte frame, as the code below shows. That overhead is negligible for a file transfer and dominant for chatty small messages, which is exactly why protocols batch.

Try the working example

python
import struct

# Start at the top of the stack: the data the application wants to send.
data = b"hello"

# L4 transport: prepend src port, dst port, segment length.
l4_header = struct.pack("!HHH", 51000, 443, 6 + len(data))
segment = l4_header + data

# L3 network: prepend version, ttl, protocol, then src and dst IPv4.
l3_header = (struct.pack("!BBB", 4, 64, 6)
             + bytes([192, 0, 2, 15])
             + bytes([198, 51, 100, 34]))
packet = l3_header + segment

# L2 link: prepend dst MAC, src MAC, ethertype (0x0800 = IPv4).
l2_header = (bytes.fromhex("aabbccddeeff")
             + bytes.fromhex("112233445566")
             + struct.pack("!H", 0x0800))
frame = l2_header + packet

units = [
    ("L7 data", data, 0),
    ("L4 segment", segment, len(l4_header)),
    ("L3 packet", packet, len(l3_header)),
    ("L2 frame", frame, len(l2_header)),
]
print("%-11s %6s %7s %8s" % ("unit", "total", "header", "payload"))
print("-" * 36)
for name, unit, hdr in units:
    print("%-11s %6d %7d %8d" % (name, len(unit), hdr, len(unit) - hdr))
print()

print("the frame is one flat byte string, built from these pieces:")
print("  L2 header:", l2_header.hex())
print("  L3 header:", l3_header.hex())
print("  L4 header:", l4_header.hex())
print("  L7 data  :", data.hex())
print()

hex_frame = frame.hex()
print("full frame (%d bytes):" % len(frame))
for i in range(0, len(hex_frame), 56):
    print("  ", hex_frame[i:i + 56])
print()

print("total header overhead :", len(frame) - len(data), "bytes")
print("payload efficiency    :", round(100 * len(data) / len(frame), 1), "%")

# Decapsulation: the receiver strips the same headers in reverse order.
recovered = frame[len(l2_header):][len(l3_header):][len(l4_header):]
print("recovered payload     :", recovered.decode())
You should see
unit         total  header  payload
------------------------------------
L7 data          5       0        5
L4 segment      11       6        5
L3 packet       22      11       11
L2 frame        36      14       22

the frame is one flat byte string, built from these pieces:
  L2 header: aabbccddeeff1122334455660800
  L3 header: 044006c000020fc6336422
  L4 header: c73801bb000b
  L7 data  : 68656c6c6f

full frame (36 bytes):
   aabbccddeeff1122334455660800044006c000020fc6336422c73801
   bb000b68656c6c6f

total header overhead : 31 bytes
payload efficiency    : 13.9 %
recovered payload     : hello

5-minute try-it

Change data from b"hello" to a 1400-byte payload (for example b"x" * 1400) and see how payload efficiency changes. Then loop over payload sizes 1, 10, 100, and 1000, printing the efficiency for each, and decide at what size the header overhead stops mattering.

One important caution

Thinking encapsulation transforms the data — each layer only prepends a header; the original bytes survive untouched inside the frame, which is why you can read them straight out of a capture

Hunting for OSI layers 5 (session) and 6 (presentation) in a real stack — TCP/IP has no separate layers for them; they are folded into the application layer

RFC 1122 — Requirements for Internet Hosts (Communication Layers)Computer Networking

Easy traps

  • Thinking encapsulation transforms the data — each layer only prepends a header; the original bytes survive untouched inside the frame, which is why you can read them straight out of a capture
  • Hunting for OSI layers 5 (session) and 6 (presentation) in a real stack — TCP/IP has no separate layers for them; they are folded into the application layer
  • Validate sample code in a local or test environment before applying it to a production network.

Exercise

Change data from b"hello" to a 1400-byte payload (for example b"x" * 1400) and see how payload efficiency changes. Then loop over payload sizes 1, 10, 100, and 1000, printing the efficiency for each, and decide at what size the header overhead stops mattering.

You'll know it worked when: unit total header payload ------------------------------------ L7 data 5 0 5 L4 segment 11 6 5 L3 packet 22 11 11 L2 frame 36 14 22 the frame is one flat byte string, built from these pieces: L2 header: aabbccddeeff1122334455660800 L3 header: 044006c000020fc6336422 L4 header: c73801bb000b L7 data : 68656c6c6f full frame (36 bytes): aabbccddeeff1122334455660800044006c000020fc6336422c73801 bb000b68656c6c6f total header overhead : 31 bytes payload efficiency : 13.9 % recovered payload : hello

The OSI and TCP/IP Models | Thuta Learning