w3resource

Rust Concurrent Web Server with Threads

Rust Threads and Synchronization: Exercise-5 with Solution

Write a Rust program that simulates a simple concurrent web server using threads.

Sample Solution:

Rust Code:

use std::net::{TcpListener, TcpStream}; // Import necessary networking modules
use std::io::{Read, Write}; // Import modules for reading from and writing to streams
use std::thread; // Import module for creating threads

// Define a function to handle each client connection
fn handle_client(mut stream: TcpStream) {
    let mut buffer = [0; 512]; // Create a buffer to store incoming data

    // Read data from the stream into the buffer
    stream.read(&mut buffer).unwrap();

    // Convert the data to a string
    let request = String::from_utf8_lossy(&buffer[..]);

    // Print the received request
    println!("Received request: {}", request);

    // Define a simple HTTP response
    let response = "HTTP/1.1 200 OK\r\n\r\nHello, World!";

    // Write the response back to the client
    stream.write(response.as_bytes()).unwrap();

    // Flush the stream to ensure all data is sent
    stream.flush().unwrap();
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); // Create a TCP listener on localhost port 8080

    println!("Server listening on port 8080...");

    // Accept incoming connections and handle them concurrently using threads
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                // Spawn a new thread to handle each client connection
                thread::spawn(move || {
                    handle_client(stream); // Call the handle_client function for each client
                });
            }
            Err(e) => {
                // Print an error message if there's an issue accepting a connection
                println!("Error accepting connection: {}", e);
            }
        }
    }
}

Output:

Server listening on port 8080...

Explanation:

In the exercise above,

  • Import the necessary modules from the standard library (std::net, std::io, and std::thread) for handling networking, input/output operations, and concurrency with threads.
  • Next, we define a function called "handle_client()", which takes a 'TcpStream' representing a client connection. Inside this function, we read data from the stream, print the received request, construct a simple HTTP response, and write the response back to the client.
  • In the main function, we create a TCP listener bound to 127.0.0.1:8080, which means it listens for incoming connections on localhost at port 8080.
  • We print a message indicating that the server is listening on port 8080.
  • We enter a loop where we continuously accept incoming connections using the listener.incoming() method. This method returns an iterator of incoming connections represented as Result<TcpStream, std::io::Error>.
  • Inside the loop, for each incoming connection, we spawn a new thread using thread::spawn. This allows us to handle multiple connections concurrently. We pass the incoming 'TcpStream' to the "handle_client()" function in the spawned thread.
  • If there's an error accepting a connection, we print an error message.

Rust Code Editor:

Previous: Rust Program: Matrix Multiplication with Parallel Threads.
Next: Rust Concurrent Task Scheduler with Threads.

What is the difficulty level of this exercise?

Test your Programming skills with w3resource's quiz.



Follow us on Facebook and Twitter for latest update.