AlgoInsight

Free lesson · Computer Networking

Server socket creation (simplified)

Easy10 min readnetworkingcomputer-networkstcp-ip

From Host-to-Host to Process-to-Process

The Network Layer (IP) solves the problem of getting packets from one machine to another machine across the internet. But that is not enough. A single machine runs dozens - sometimes hundreds - of applications simultaneously. Your laptop might have a web browser, a Slack client, a Spotify stream, an SSH session, and a background software update all communicating over the network at the same time. When a packet arrives at your machine, IP has delivered it to the correct host. But which application should receive it?

The Transport Layer solves this problem. It extends the Network Layer's host-to-host delivery into process-to-process delivery - ensuring that each packet reaches the correct application on the correct machine. It is the layer that makes it possible for multiple applications to share a single network connection without interfering with each other, and it provides the reliability and ordering guarantees that most applications depend on.

The Transport Layer sits between the Application Layer (which produces data - HTTP requests, database queries, video streams) and the Network Layer (which moves packets across the internet). It provides the interface that applications use to send and receive data over the network. When you write socket.connect() in your code, you are interacting with the Transport Layer.

The two dominant transport protocols are TCP (Transmission Control Protocol) and UDP (User Datagram Protocol). TCP provides reliable, ordered, connection-oriented delivery. UDP provides fast, unordered, connectionless delivery. This module dives deep into TCP - the protocol that carries the vast majority of internet traffic, including web browsing, API calls, database queries, email, file transfers, and most other applications. UDP is covered in the next module.

Port Numbers - The Transport Layer's Addressing System

IP addresses identify machines. Port numbers identify applications on those machines. Together, an IP address and a port number form a socket address that uniquely identifies a specific application on a specific machine anywhere on the internet.

Port numbers are 16-bit unsigned integers, ranging from 0 to 65,535. This gives each host up to 65,536 possible ports - enough for many simultaneous connections but not unlimited, which is why port exhaustion is a real operational concern in high-connection-count environments like load balancers and microservice gateways. Ports are divided into three ranges:

Range Name Purpose
0–1,023 Well-Known Ports Reserved for standard services. Assigned by IANA. Require root/admin privileges to bind on most operating systems.
1,024–49,151 Registered Ports Used by specific applications. Registered with IANA but not as strictly controlled.
49,152–65,535 Dynamic/Ephemeral Ports Used by the OS for temporary client-side connections. Assigned automatically when a client initiates a connection.

Some well-known ports every engineer should memorize:

Port Protocol Service
22 TCP SSH (Secure Shell)
25 TCP SMTP (Email sending)
53 TCP/UDP DNS (Domain Name System)
80 TCP HTTP (Web traffic)
443 TCP HTTPS (Encrypted web traffic)
3306 TCP MySQL
5432 TCP PostgreSQL
6379 TCP Redis
8080 TCP HTTP alternative (common for dev servers)
27017 TCP MongoDB

When your browser connects to https://google.com, it creates a TCP connection from your machine's IP address on an ephemeral port (say, 192.168.1.10:52431) to Google's server on port 443 (142.250.80.46:443). The combination of source IP, source port, destination IP, and destination port - the 4-tuple - uniquely identifies this specific connection among all the connections on the internet.

Multiplexing and Demultiplexing

The Transport Layer performs two critical operations:

Multiplexing (at the sender): Multiple applications on the same machine each generate data. The Transport Layer collects data from each application, attaches the correct source and destination port numbers, and passes the resulting segments to the Network Layer for transmission. Multiple application streams are multiplexed into a single network connection.

Demultiplexing (at the receiver): When segments arrive at the destination machine, the Transport Layer examines the destination port number and delivers each segment to the correct application. Multiple incoming streams are demultiplexed to their respective applications.

This is why port numbers exist - they are the demultiplexing keys that tell the Transport Layer which application should receive each incoming segment.

graph TD
    subgraph Sender["Sending Host"]
        APP1["Web Browser<br/>Port 52431"]
        APP2["Slack<br/>Port 52432"]
        APP3["SSH<br/>Port 52433"]
        APP1 --> MUX["Transport Layer<br/>MULTIPLEXING<br/>(attach port numbers)"]
        APP2 --> MUX
        APP3 --> MUX
        MUX --> NET["Network Layer<br/>(send packets)"]
    end

    subgraph Receiver["Receiving Host"]
        NET2["Network Layer<br/>(receive packets)"] --> DEMUX["Transport Layer<br/>DEMULTIPLEXING<br/>(read port numbers)"]
        DEMUX --> SRV1["Web Server<br/>Port 443"]
        DEMUX --> SRV2["Slack Server<br/>Port 443"]
        DEMUX --> SRV3["SSH Server<br/>Port 22"]
    end

    style APP1 fill:#4f46e5,stroke:#4338ca,color:#fff
    style APP2 fill:#7c3aed,stroke:#6d28d9,color:#fff
    style APP3 fill:#8b5cf6,stroke:#7c3aed,color:#fff
    style MUX fill:#a78bfa,stroke:#8b5cf6,color:#fff
    style NET fill:#c4b5fd,stroke:#a78bfa,color:#000
    style NET2 fill:#c4b5fd,stroke:#a78bfa,color:#000
    style DEMUX fill:#a78bfa,stroke:#8b5cf6,color:#fff
    style SRV1 fill:#4f46e5,stroke:#4338ca,color:#fff
    style SRV2 fill:#7c3aed,stroke:#6d28d9,color:#fff
    style SRV3 fill:#8b5cf6,stroke:#7c3aed,color:#fff
This diagram shows multiplexing and demultiplexing. On the sending host, three applications - a web browser on port 52431, Slack on port 52432, and SSH on port 52433 - each send data to the Transport Layer. The Transport Layer multiplexes them by attaching port numbers and passes the segments to the Network Layer. On the receiving host, the Network Layer delivers incoming packets to the Transport Layer, which demultiplexes them by reading the destination port number and delivering each segment to the correct application: web server on port 443, Slack server on port 443, or SSH server on port 22.

The Socket Abstraction

Applications do not interact with the Transport Layer directly through raw segments and port numbers. Instead, they use the socket API - a programming interface that abstracts the complexities of network communication into a set of familiar operations: create, bind, listen, connect, send, receive, close.

A socket is an endpoint for communication. It is identified by a combination of IP address and port number. When a server application calls bind(port 443) and listen(), it creates a socket that accepts incoming connections on port 443. When a client calls connect(server_ip, 443), it creates a socket that initiates a connection to the server.

The socket API was originally developed for BSD Unix in 1983 (the "Berkeley sockets" API) and has been adopted by virtually every operating system and programming language since. Whether you write network code in Python, Java, Go, Rust, or C, you use some form of the socket API. The actual system calls differ slightly, but the conceptual model is universal:

# Server socket creation (simplified)
import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # Create TCP socket
server.bind(('0.0.0.0', 8080))  # Bind to port 8080 on all interfaces
server.listen(5)                 # Start listening, queue up to 5 connections

while True:
    client_socket, address = server.accept()  # Accept incoming connection
    data = client_socket.recv(1024)           # Read data from client
    client_socket.send(b'Hello!')             # Send data to client
    client_socket.close()                     # Close connection

SOCK_STREAM creates a TCP socket (stream-oriented, reliable, ordered). SOCK_DGRAM creates a UDP socket (datagram-oriented, unreliable, unordered). This single parameter determines which transport protocol your application uses - and consequently whether you get reliability guarantees or raw speed.

Connection-Oriented vs Connectionless

TCP is connection-oriented: before any data can be exchanged, the client and server must establish a connection through a handshake (the three-way handshake covered in the next topic). The connection maintains state (sequence numbers, window sizes, congestion parameters) that both sides track for the duration of the communication. When communication is finished, the connection is explicitly closed through a teardown process. This connection state is what enables TCP to provide reliability, ordering, and flow control - but it also means TCP incurs latency overhead (at least one round trip for the handshake) and consumes memory on both endpoints to maintain the state.

UDP is connectionless: there is no handshake, no connection state, and no teardown. The sender simply sends datagrams to the destination address and port. There is no guarantee that the datagrams arrive, arrive in order, or arrive at all. The sender does not even know if the destination exists or is listening. This simplicity is what makes UDP faster than TCP - no handshake latency (saving at least one round-trip time), no per-connection state overhead (the OS does not need to maintain connection tables), and no retransmission delays (lost data is simply gone, not re-sent).

The choice between TCP and UDP is one of the most fundamental design decisions in network application development. Most applications use TCP because reliability is more important than speed - a web page with missing bytes is broken, a database query with lost data is corrupt. Applications where timeliness matters more than completeness - real-time video (where a dropped frame is better than a delayed frame that arrives after the viewer has moved on), DNS queries (where retransmission at the application level is cheaper than TCP connection overhead), and online gaming (where low latency matters more than perfect delivery of every position update) - use UDP.

TCP and UDP Header Overview

At the Transport Layer, data is organized into segments (TCP) or datagrams (UDP). Each segment or datagram includes a header that carries the information the Transport Layer needs to perform multiplexing, demultiplexing, and (for TCP) reliability and flow control.

The TCP Header

The TCP header is a minimum of 20 bytes and contains critical fields:

Field Size Purpose
Source Port 16 bits Identifies the sending application
Destination Port 16 bits Identifies the receiving application
Sequence Number 32 bits Position of this segment's data in the byte stream
Acknowledgment Number 32 bits Next byte expected from the other side
Data Offset 4 bits Header length (in 32-bit words)
Flags (SYN, ACK, FIN, RST, PSH, URG) 6 bits Control flags for connection management
Window Size 16 bits Flow control - how much data the receiver can accept
Checksum 16 bits Error detection for the entire segment
Urgent Pointer 16 bits Used with the URG flag for priority data

The TCP header's complexity reflects the protocol's ambition: reliable, ordered, flow-controlled, congestion-aware delivery. Every field serves a purpose that you will encounter in the topics that follow - sequence numbers for ordering, acknowledgment numbers for reliability, window size for flow control, and flags for connection management.

The UDP Header

The UDP header is only 8 bytes - dramatically simpler:

Field Size Purpose
Source Port 16 bits Identifies the sending application
Destination Port 16 bits Identifies the receiving application
Length 16 bits Total datagram length
Checksum 16 bits Error detection (optional in IPv4, mandatory in IPv6)

UDP's simplicity is its strength. No sequence numbers, no acknowledgments, no window sizes, no connection state. The application gets raw speed at the cost of having no delivery guarantees. Applications that use UDP must implement their own reliability mechanisms if they need them - or accept that some data may be lost.

TCP vs UDP - A First Look

This module focuses on TCP. The next module covers UDP. Here is a preview of the key differences:

Feature TCP UDP
Connection Connection-oriented (handshake required) Connectionless (no handshake)
Reliability Guaranteed delivery with acknowledgments Best-effort, no delivery guarantee
Ordering Data delivered in order No ordering guarantee
Flow control Yes (sliding window) No
Congestion control Yes (slow start, AIMD) No
Overhead 20-byte minimum header 8-byte fixed header
Use cases Web, APIs, databases, email, file transfer Video streaming, gaming, DNS, VoIP
graph LR
    subgraph TransportChoice["Transport Protocol Decision"]
        direction TB
        Q["Does your application<br/>need reliable, ordered<br/>delivery?"]
        Q -->|"Yes"| TCP["TCP<br/>Web, APIs, databases,<br/>file transfers, email"]
        Q -->|"No - speed and<br/>low latency matter<br/>more"| UDP["UDP<br/>Video, gaming, DNS,<br/>VoIP, real-time data"]
    end

    style Q fill:#4f46e5,stroke:#4338ca,color:#fff
    style TCP fill:#22c55e,stroke:#16a34a,color:#fff
    style UDP fill:#7c3aed,stroke:#6d28d9,color:#fff
This diagram shows the transport protocol decision. The central question is whether the application needs reliable, ordered delivery. If yes, TCP is the choice, used for web, APIs, databases, file transfers, and email. If speed and low latency matter more than perfect delivery, UDP is the choice, used for video streaming, gaming, DNS, VoIP, and real-time data.

Interview: Transport Layer knowledge appears in every System Design interview:

"What protocol does your service use?" - Almost always TCP (via HTTP/HTTPS). Know why: reliability, ordering, congestion control. If you choose UDP, you must justify it - what makes this use case different enough to give up reliability?

"What port does your database run on?" - PostgreSQL: 5432. MySQL: 3306. Redis: 6379. MongoDB: 27017. Knowing these by heart demonstrates operational fluency.

"Can two applications on the same server use the same port?" - No, not with the same protocol and IP. A port can only be bound by one process at a time (unless using SO_REUSEPORT for load balancing). This is why deploying multiple services on the same host requires different ports or a reverse proxy.

"What is the difference between a socket and a port?" - A port is a number (0-65535). A socket is an endpoint identified by the combination of IP address and port. Multiple sockets can use the same port on the same machine - a server listening on port 443 creates a new socket for each accepted client connection, all sharing port 443 on the server side but differentiated by the client's IP and port.

What Comes Next

The next topic covers the TCP three-way handshake - the sequence of SYN, SYN-ACK, and ACK messages that establishes a TCP connection. Understanding the handshake explains why TCP connections have latency overhead, how sequence numbers are initialized, and what happens during the critical first milliseconds of every TCP connection you will ever make.

Exercise: Starter: Run netstat -tuln (Linux) or lsof -i -P (Mac) on your machine to see all active listening sockets. Which ports are open? Can you identify which application is listening on each port? Try running a simple Python HTTP server (python3 -m http.server 8080) and verify it appears in the listing.

Intermediate: Write a simple TCP echo server and client in Python. The server should listen on port 9999, accept a connection, read data, echo it back, and close the connection. The client should connect, send "Hello", print the response, and close. Run both and observe the connection. Then modify the client to connect from two different terminals simultaneously - what happens?

Advanced: Research the SO_REUSEPORT socket option. How does it allow multiple processes to bind to the same port? How do modern web servers like Nginx use SO_REUSEPORT to distribute incoming connections across worker processes? What is the difference between SO_REUSEADDR and SO_REUSEPORT, and when would you use each? How does this relate to the "thundering herd" problem in multi-process servers?

Back to Computer Networking