P2P Networks From Scratch: The Revolution of Decentralization

It is 2008. Banks are collapsing, governments are bailing out corporations, and people are losing trust in centralized institutions. In a small corner of the internet, someone releases software that lets computers talk directly to each other - no banks, no corporations, no central authority needed. This isn’t just Bitcoin. It’s an entire philosophy: peer-to-peer networks.

Today, when you download a movie via BitTorrent, send money via Bitcoin, or make a video call, you’re participating in a quiet revolution against centralized control. But how do these networks actually work? And why can’t we just connect everyone to everyone else?

Why This Actually Matters

Before we dive into the technical details, let’s see why P2P is revolutionary:

File Sharing: Record labels sued Napster and shut it down in 2001. BitTorrent? Still going strong after 20+ years because there’s no central server to shut down.

Money: Banks can freeze your account. Bitcoin? Your wallet, your money, no permission needed.

Communication: Governments can block Facebook. Mesh networks? Work even when authorities cut the internet cables.

The technical details matter because they enable total freedom of control, censorship resistance, and resilience against failures.

What is P2P?

In the traditional internet, your computer talks to servers to get information. In P2P, your computer talks directly to other computers (peers).

graph LR P1["Your Computer"] --- P2["Peer 1"] P1 --- P3["Peer 2"] P2 --- P3 P2 --- P4["Peer 3"] P3 --- P4

BitTorrent is a very popular P2P protocol used for sharing files. When you download a file using BitTorrent, you connect to many other peers who have parts of the file.

Bitcoin also uses peer-to-peer networking to share transaction data and maintain the blockchain - that is what makes it revolutionary.

Some other modern peer-to-peer systems include:

  • IPFS (InterPlanetary File System): A decentralized file storage system
  • WebRTC: Enables peer-to-peer connections in web browsers for video calls and file sharing

These systems have no central server, making them more resilient and harder to censor. They don’t rely on a single point of failure or a single entity controlling the data.

Building Your First P2P Network

Let’s build a simple P2P network to understand the fundamentals. The basic idea is that each peer is both a client and a server - it has a socket server listening for incoming connections and also acts as a client that connects to other peers.

A basic implementation in Go could look like this:

type Peer struct {
    ID       string
    Name     string
    Address  string
    Conn     net.Conn
    LastSeen time.Time
}

type P2PNode struct {
    ID            string
    Port          int
    Peers         map[string]*Peer     // Connected peers
    KnownPeers    map[string]time.Time // Discovered peers
    Listener      net.Listener
    BootstrapIP   string
    BootstrapPort int
}

The bootstrap node is just a known IP address and port of a peer that is already connected to the network. New peers can connect to this bootstrap node to discover other peers.

The following diagram illustrates what peers really look from the inside. (Bunch of sockets, just managed right) (3 Peers example):

graph TB subgraph "Peer A" A1[Listener Socket :8080] A2[Socket → Peer B] A3[Socket → Peer C] end subgraph "Peer B" B1[Listener Socket :8081] B2[Socket → Peer A] B3[Socket → Peer C] end subgraph "Peer C" C1[Listener Socket :8082] C2[Socket → Peer A] C3[Socket → Peer B] end A2 -.-> B1 A3 -.-> C1 B2 -.-> A1 B3 -.-> C1 C2 -.-> A1 C3 -.-> B1

The Basic Rules

As we’ve seen before, a peer-to-peer network is just a program with a bunch of sockets. The secret is how we manage those sockets. The basic questions of the protocol are:

  • Discovery
  • Connection Management
  • Message Broadcasting

There is no single “right” way to do this. Different P2P networks use different strategies depending on their goals (speed, reliability, anonymity, etc). But the basic principles are the same.

What matters mostly is that these rules, tells us how to behave. When to open and to close sockets and connections. How to send and receive messages.

Let’s break down each of these rules.

Discovery: How do peers find each other?

To connect to a P2P network, a peer needs to know about at least one other peer. This can be done through:

  • Bootstrap nodes: Predefined list of known peers that new peers can connect to (used in Bitcoin, Ethereum)
  • Trackers: Central servers that help peers find each other (BitTorrent uses this)
  • DHT (Distributed Hash Table): A decentralized way for peers to find each other without a central server (used in BitTorrent, IPFS)

For a simple implementation, we can use a known IP address and port of a peer to connect to.

Connection Management: How do we manage connections to other peers?

Each peer needs to manage its connections to other peers:

  • Accepting incoming connections
  • Initiating outgoing connections
  • Keeping track of connected peers
  • Handling disconnections and reconnections

This is where we mostly define the protocol and behaviour of our P2P network. We need to define some basic messages to manage connections:

A few example message types could be:

  • HELLO: Sent when a peer connects to another peer. Contains the peer’s ID and address.
  • PEER_LIST: Sent in response to HELLO, contains a list of known peers.
  • PING/PONG: Heartbeat messages to check if a peer is still alive.
  • MESSAGE: Generic message for broadcasting data to other peers.
  • GOODBYE: Sent when a peer is disconnecting.

A more detailed message format sent over the network could look like this:

| MSG_TYPE (1 byte) | PAYLOAD_LENGTH (4 bytes) | PAYLOAD (variable) |
| PEER_LIST         | 42                        | peer1_ip:port,peer2_ip:port,... |

With this format, our program can parse the message and add new peers to its known peers list.

The Full Mesh Approach

The simplest and easier way to understand P2P is to connect everyone to everyone else. This is called a “full mesh” network.

Starting Small (3 peers):

graph LR A[Alice] <--> B[Bob] B <--> C[Charlie] A <--> C

For 3 people, each peer needs 2 connections, so total connections = 3 × (3-1) / 2 = 3 connections.

Growing the Network (5 peers):

graph LR A2[Alice] --- B2[Bob] A2 --- C2[Charlie] A2 --- D2[Dave] A2 --- E2[Eve] B2 --- C2 B2 --- D2 B2 --- E2 C2 --- D2 C2 --- E2 D2 --- E2

5 people = 10 connections total. Still manageable. ✅

What are the rules of our simple P2P network?

Startup

When starting the network we need a first ever peer. This will be an option in our program to start as a bootstrap node. The bootstrap node is just a known IP address and port of a peer that is already connected to the network. New peers can connect to this bootstrap node to discover other peers.

sequenceDiagram participant Peer1 as Peer 1 (Bootstrap) participant Peer2 as Peer 2 participant Peer3 as Peer 3 Peer2->>Peer1: Connect Peer1->>Peer2: Send known peers list Peer2->>Peer3: Connect Peer3->>Peer2: Send known peers list

Discovery

When a peer starts, it connects to a known bootstrap node to get a list of other peers. It then tries to connect to all of them.

sequenceDiagram participant NewPeer as New Peer participant Bootstrap as Bootstrap Node participant KnownPeer1 as Known Peer 1 participant KnownPeer2 as Known Peer 2 NewPeer->>Bootstrap: Connect Bootstrap->>NewPeer: Send known peers list (KnownPeer1, KnownPeer2) NewPeer->>KnownPeer1: Connect NewPeer->>KnownPeer2: Connect

Connection Management

Each peer keeps track of its connected peers. If a connection drops, it tries to reconnect or find new peers from its known peers list.

sequenceDiagram participant PeerA as Peer A participant PeerB as Peer B PeerA->>PeerB: Heartbeat PeerB-->>PeerA: Heartbeat Ack Note over PeerA,PeerB: Connection healthy PeerA->>PeerB: Heartbeat Note over PeerA,PeerB: No response (connection lost) PeerA->>PeerB: Try to reconnect PeerB-->>PeerA: Reconnected

The Scaling Problem of Full Mesh Networks

There is a reason why full mesh networks are not used in big peer-to-peer systems, the scaling problem. The general formula for connections in a full mesh network is:

$$\text{Connections} = \frac{N \times (N - 1)}{2}$$

Where N is the number of peers.

The Scaling Nightmare:

People Connections Status
5 10 “Works like a charm”
10 45 “Still okay”
25 300 “Getting heavy”
50 1,225 “Uh oh…”
100 4,950 “Not scalable!”

Why can’t we just have more connections?

  • File descriptor limit: Most systems default to ~1,000-4,000 connections (though configurable)
  • Memory explosion: Each connection needs 64KB+ of memory buffers
  • Bandwidth death: Sending one message to 999 people simultaneously
  • Maintenance overhead: Constant “are you still there?” messages between everyone

This approach works fine for small networks (≤20 peers), but quickly becomes impractical as the network grows.

How Real P2P Networks Actually Work

Partial Mesh Networks

The network architecture is more of a “partial mesh” or “random graph” rather than a full mesh. Key features include:

Message forwarding: Messages get relayed through the network, not sent directly to everyone. Each peer only needs to connect to a few others, and messages can still reach everyone eventually.

This is often referred to as a “gossip protocol” or “epidemic protocol”, where information spreads like a rumor.

graph TD A[A] --> B[B] A --> C[C] B --> D[D] B --> E[E] C --> E C --> F[F] D --> G[G] E --> G E --> H[H] F --> H

With this approach, BitTorrent can handle millions of users sharing files simultaneously without overwhelming any single peer or the network.

The Message Duplication Problem

But there’s a catch with message forwarding:

graph LR A["A: Hello"] --> B[B] A --> C[C] B --> C C --> B style A fill:#ff9999 style B fill:#ffcc99 style C fill:#99ccff

Without forwarding (our simple code):

  • A sends “Hello” → B gets it, C doesn’t
  • Limited reach but no duplicates

With forwarding (real P2P):

  • A → B: “Hello”
  • A → C: “Hello”
  • B → C: “Hello” (duplicate!)
  • C → B: “Hello” (duplicate!)
  • Message storm!

How to solve this: P2P networks use message identifiers, “seen” lists to track processed messages, TTL (Time To Live) for messages, and smart flooding strategies to limit the number of peers each message is forwarded to.

NAT Traversal and Hole Punching

In real life, many peers are behind NATs (Network Address Translators) and firewalls. This means they don’t have a public IP address and can’t accept incoming connections directly.

P2P networks solve this using techniques like hole punching:

sequenceDiagram participant PeerA as Peer A (behind NAT) participant Server as Coordination Server participant PeerB as Peer B (behind NAT) PeerA->>Server: "I want to connect to Peer B" PeerB->>Server: "I want to connect to Peer A" Server->>PeerA: "Peer B is at IP:Port" Server->>PeerB: "Peer A is at IP:Port" Note over PeerA,PeerB: Both peers simultaneously send packets PeerA-->>PeerB: Direct connection established PeerB-->>PeerA: NAT mappings created

This works because the NAT creates a temporary mapping for outgoing packets, allowing incoming packets from the same external address and port. This clever trick allows peers to connect directly even when behind NATs.

The coordination server doesn’t need to be centralized - it can be any peer that is publicly reachable.

Conclusion

Designing a peer-to-peer network is a fascinating challenge that combines networking, distributed systems, and protocol design. It is a completely different mindset from traditional client-server architectures, and requires careful thought about every aspect of the system.

It might be straightforward for small groups, but scaling requires careful planning and understanding of network topologies. The naive “connect everyone to everyone” approach breaks down quickly due to the quadratic growth in connections.

Real P2P networks like BitTorrent solve this through:

  • Smart peer selection (connect to ~30-80 peers instead of everyone)
  • Message forwarding with deduplication
  • NAT traversal techniques for real-world deployment
  • Distributed discovery mechanisms (DHT, trackers, bootstrap nodes)

Try It Yourself

  • The code: Simple P2P implementation you can run
  • Experiment: Watch it work with 3 peers, observe scaling challenges with 10
  • Learn: See the scaling problems firsthand
  • Appreciate: How much engineering goes into “simple” systems like BitTorrent