How to Build a Multithreaded Web Server in Rust Without External Crates

How to Build a Multithreaded Web Server in Rust Without External Crates Rust’s powerful concurrency model and ownership system make it an excellent choice for building fast, safe web servers. In this article, you’ll learn how to implement a multithreaded web server from scratch using only the Rust standard library. 1. Project Setup Start with a new Rust project: cargo new rust_web_server cd rust_web_server 2. Reading and Responding to HTTP Requests Edit src/main.rs to include basic TCP listening and response logic: use std::io::prelude::*; use std::net::{TcpListener, TcpStream}; use std::thread; use std::fs; fn handle_connection(mut stream: TcpStream) { let mut buffer = [0; 1024]; stream.read(&mut buffer).unwrap(); let contents = fs::read_to_string("hello.html").unwrap(); let response = format!( "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", contents.len(), contents ); stream.write(response.as_bytes()).unwrap(); stream.flush().unwrap(); } 3. Adding a Thread Pool To handle requests concurrently, we'll build a basic thread pool without any external dependencies: use std::sync::{mpsc, Arc, Mutex}; struct ThreadPool { workers: Vec, sender: mpsc::Sender, } type Job = Box Worker { let thread = thread::spawn(move || loop { let job = receiver.lock().unwrap().recv().unwrap(); println!("Worker {} got a job; executing.", id); job(); }); Worker { id, thread: Some(thread), } } } 4. Wiring It All Together fn main() { let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); let pool = ThreadPool::new(4); for stream in listener.incoming().take(10) { let stream = stream.unwrap(); pool.execute(|| { handle_connection(stream); }); } println!("Shutting down server."); } 5. Testing Create a file named hello.html in your project root: Rust Web Server Hello from Rust! Conclusion This is a barebones but fully functioning multithreaded web server written entirely with the Rust standard library. From here, you can explore features like routing, middleware, and async IO using more advanced tools like tokio or hyper. If this post helped you, consider supporting me: buymeacoffee.com/hexshift

Apr 16, 2025 - 11:04
 0
How to Build a Multithreaded Web Server in Rust Without External Crates

How to Build a Multithreaded Web Server in Rust Without External Crates

Rust’s powerful concurrency model and ownership system make it an excellent choice for building fast, safe web servers. In this article, you’ll learn how to implement a multithreaded web server from scratch using only the Rust standard library.

1. Project Setup

Start with a new Rust project:

cargo new rust_web_server
cd rust_web_server

2. Reading and Responding to HTTP Requests

Edit src/main.rs to include basic TCP listening and response logic:

use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};
use std::thread;
use std::fs;

fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();

    let contents = fs::read_to_string("hello.html").unwrap();
    let response = format!(
        "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}",
        contents.len(),
        contents
    );

    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}

3. Adding a Thread Pool

To handle requests concurrently, we'll build a basic thread pool without any external dependencies:

use std::sync::{mpsc, Arc, Mutex};

struct ThreadPool {
    workers: Vec,
    sender: mpsc::Sender,
}

type Job = Box;

impl ThreadPool {
    fn new(size: usize) -> ThreadPool {
        let (sender, receiver) = mpsc::channel();
        let receiver = Arc::new(Mutex::new(receiver));

        let mut workers = Vec::with_capacity(size);
        for id in 0..size {
            workers.push(Worker::new(id, Arc::clone(&receiver)));
        }

        ThreadPool { workers, sender }
    }

    fn execute(&self, f: F)
    where
        F: FnOnce() + Send + 'static,
    {
        self.sender.send(Box::new(f)).unwrap();
    }
}

struct Worker {
    id: usize,
    thread: Option>,
}

impl Worker {
    fn new(id: usize, receiver: Arc>>) -> Worker {
        let thread = thread::spawn(move || loop {
            let job = receiver.lock().unwrap().recv().unwrap();
            println!("Worker {} got a job; executing.", id);
            job();
        });

        Worker {
            id,
            thread: Some(thread),
        }
    }
}

4. Wiring It All Together

fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    let pool = ThreadPool::new(4);

    for stream in listener.incoming().take(10) {
        let stream = stream.unwrap();
        pool.execute(|| {
            handle_connection(stream);
        });
    }

    println!("Shutting down server.");
}

5. Testing

Create a file named hello.html in your project root:



Rust Web Server

Hello from Rust!

Conclusion

This is a barebones but fully functioning multithreaded web server written entirely with the Rust standard library. From here, you can explore features like routing, middleware, and async IO using more advanced tools like tokio or hyper.

If this post helped you, consider supporting me: buymeacoffee.com/hexshift