A BitTorrent client built from scratch in C# following the BitTorrent protocol specification. The project implements the core protocol: bencode parsing, torrent file reading, tracker communication, peer wire protocol, and piece management with SHA1 verification.
Built as a learning project to understand peer-to-peer networking, binary protocols, and concurrent programming. Based on Sean O'Flynn's tutorial, restructured with clean architecture, SOLID principles, and design patterns.
The project is organized into six layers, each with a single responsibility:
bitTorrent/
├── BEncoding/ Bencode parser (decode + encode)
│ ├── AST.cs Value types: string, integer, list, dictionary
│ ├── ByteReader.cs Cursor over byte arrays
│ ├── IBencodeParser.cs Parser interface
│ └── BEncodingParser.cs Recursive descent parser
│
├── Torrent/ Torrent metadata
│ ├── FileItem.cs File path, size, offset
│ ├── Torrent.cs Immutable metadata container
│ └── TorrentParser.cs Converts parsed bencode to Torrent object
│
├── PieceManager/ Disk I/O and verification
│ └── PieceManager.cs Read/write blocks, SHA1 piece verification
│
├── Tracker/ Tracker communication
│ ├── ITracker.cs Tracker interface (Open/Closed principle)
│ ├── TrackerResponse.cs Peer list and request interval
│ └── HttpTracker.cs HTTP tracker implementation
│
├── Peer/ Peer wire protocol
│ ├── MessageType.cs Protocol message type enum
│ ├── PeerMessageCodec.cs Binary message encoding/decoding
│ ├── DataRequest.cs Block request data
│ ├── DataPackage.cs Block received data
│ └── Peer.cs TCP connection, state, send/receive
│
├── Client/ Engine that ties everything together
│ ├── TorrentClient.cs Orchestrates trackers, peers, downloads, uploads
│ └── Throttle.cs Bandwidth limiting
│
└── Program.cs Entry point
-
Parse a
.torrentfile using the bencode decoder into aTorrentobject containing metadata, piece hashes, and tracker URLs. -
Announce to trackers, sending the torrent's infohash (SHA1 of the encoded info dictionary). The tracker responds with a list of peer IP addresses.
-
Connect to peers over TCP. Both sides exchange handshakes (verifying they're talking about the same torrent) and bitfields (communicating which pieces each side has).
-
Download by requesting blocks from peers that have pieces we need. Pieces are selected by a scoring algorithm that prioritizes completion progress, rarity, and randomness.
-
Verify each completed piece by computing its SHA1 hash and comparing against the hash from the torrent file. If verification fails, the piece is re-downloaded.
-
Upload pieces to other peers that request them, with bandwidth throttling.
Separation of concerns over tutorial simplicity. The original tutorial puts everything in a monolithic Torrent class. This project splits responsibilities: Torrent holds metadata, PieceManager handles disk I/O, TorrentParser handles parsing, and TorrentClient orchestrates.
Interfaces for extensibility. IBencodeParser and ITracker allow swapping implementations without changing dependent code. For example, adding a UDP tracker only requires a new UdpTracker class implementing ITracker.
Dependency injection. Classes receive their dependencies through constructors rather than creating them internally. TorrentParser receives an IBencodeParser, HttpTracker receives an IBencodeParser.
Immutable data objects. Torrent, FileItem, and the bencode AST types are immutable after construction, preventing accidental mutation of shared state.
Binary data preservation. BencodeString stores raw byte[] internally, not string, because bencode "strings" often contain binary data (SHA1 hashes) that would be corrupted by UTF-8 encoding/decoding.
- Bencode encoding/decoding — recursive descent parser, round-trip verified
- SHA1 hashing — infohash computation, piece verification
- TCP networking — async reads, message framing over a byte stream
- Binary protocol — big-endian integer encoding, bitfield manipulation
- Multithreading — concurrent dictionaries, interlocked operations, thread-safe throttling
- File I/O — reading/writing across file boundaries, piece-to-file offset mapping
dotnet build
dotnet run --project bitTorrent -- 6881 path/to/file.torrent path/to/download/directorydotnet test75 unit tests covering bencode parsing, byte reader, message codec, piece manager, and AST types.
This is a learning implementation of BitTorrent v1.0. It does not include:
- UDP tracker protocol (only HTTP trackers)
- DHT (distributed hash table) for trackerless operation
- Peer exchange (PEX)
- Encryption (MSE/PE)
- UPnP/NAT-PMP for port forwarding
- Resume/pause functionality
- Multi-torrent support