A compact BitTorrent client written in C# and .NET 8, originally built as part of the CodeCrafters "Build Your Own BitTorrent" challenge.
This is a learning-oriented networking project. It focuses on the mechanics behind torrent metadata, tracker communication, peer handshakes, piece requests, integrity checks, and magnet links rather than trying to be a polished replacement for a full BitTorrent client.
This project explores the lower-level pieces that a BitTorrent client needs before a user interface, persistence layer, or long-running session manager can be useful.
It was built to work directly with:
- bencode decoding and encoding
.torrentmetainfo parsing- SHA-1 info hash and piece hash validation
- HTTP tracker announce requests
- compact peer list parsing
- BitTorrent peer handshakes
- interested, unchoke, bitfield, and piece messages
- block-level piece downloading
- concurrent piece downloading across discovered peers
- magnet URI parsing
- BitTorrent extension handshakes for
ut_metadata
The CLI exposes the challenge stages as direct commands:
decodedecodes bencoded valuesinfoprints tracker, file, info hash, piece length, and piece hash metadata from a.torrentfilepeersasks the tracker for peers and prints compact peer addresseshandshakeperforms a BitTorrent peer handshakedownload_piecedownloads and verifies one piece from a torrentdownloaddownloads all pieces from a torrent and writes the assembled filemagnet_parseparses a magnet URImagnet_handshakeperforms a peer handshake from a magnet URImagnet_infofetches torrent metadata through the extension protocolmagnet_download_piecedownloads one piece from a magnet URImagnet_downloaddownloads all pieces from a magnet URI
The code deliberately keeps the architecture direct:
- src/Program.cs maps CLI commands to command handlers
- src/Bencoding contains the bencode reader and writer
- src/Metadata models torrent and magnet metadata
- src/Connection contains peer connection and protocol message types
- src/Extensions/TrackerExtensions.cs handles tracker announce requests and compact peer parsing
- src/Extensions/NetworkStreamExtensions.cs handles peer protocol reads, writes, piece downloads, and piece hash verification
The implementation favors traceable protocol code over framework-style abstraction. For a project meant to demonstrate systems and protocol work, I kept the path from CLI input to network I/O easy to follow.
This is not a production BitTorrent client.
Important limitations:
- only single-file torrents are in scope
- tracker support is HTTP-oriented and minimal
- there is no DHT, PEX, peer choking strategy, resume data, or long-running session state
- peer selection and retry behavior are intentionally simple
- magnet metadata fetching currently targets the challenge-sized happy path rather than arbitrary large metadata responses
- diagnostics are written directly to the console instead of using structured logging
- there is no comprehensive automated test suite
The code is best read as a protocol implementation exercise, not as an application meant for everyday torrenting.
- Docker
You do not need a local .NET SDK for the Docker workflow below.
Run this once from the repository root:
$ docker build -t codecrafters-bittorrent-csharp .The container runs the BitTorrent CLI directly. Bind-mount the repository into /workspace so the container can read torrent files from your working tree.
$ docker run --rm -v "$PWD:/workspace" codecrafters-bittorrent-csharp info sample.torrentAsk the tracker for peers:
$ docker run --rm -v "$PWD:/workspace" codecrafters-bittorrent-csharp peers sample.torrentParse a magnet URI:
$ docker run --rm -v "$PWD:/workspace" codecrafters-bittorrent-csharp magnet_parse "magnet:?xt=urn:btih:d69f91e6b2ae4c542468d1073a71d4ea13879a7f&dn=sample&tr=http%3A%2F%2Fbittorrent-test-tracker.codecrafters.io%2Fannounce"The magnet example uses the info hash and tracker from sample.torrent. The peers command contacts the CodeCrafters tracker, so it needs outbound network access from Docker.
If you do have the .NET 8 SDK installed, the CodeCrafters helper script still works:
$ ./your_bittorrent.sh info sample.torrent
$ ./your_bittorrent.sh peers sample.torrent
$ ./your_bittorrent.sh download -o tmp/output.bin sample.torrentYou can also run the project directly:
$ dotnet run --project . --configuration Release -- info sample.torrentThe BitTorrent implementation in this repository was written by me as part of hands-on CodeCrafters practice.
AI assistance was used later for repository analysis and documentation work, including this README. The protocol implementation itself should be evaluated as a compact learning project rather than as AI-generated application scaffolding.
If I continue developing this project, the next areas I would focus on are:
- support multi-file torrents
- make peer retry behavior bounded and easier to reason about
- fetch multi-piece magnet metadata correctly
- add focused tests around bencode parsing, tracker response parsing, and piece assembly
- introduce clearer command-line validation and help output
- replace console diagnostics with structured logging