全3250文字
PR

 今月はRustの非同期処理をHTTPサーバーの開発を通して説明している。実際に手を動かすことで、Web開発の基本であるHTTPサーバーの仕組みと非同期処理の基礎を同時に学ぶことができる。

反復サーバーの実装

 HTTPサーバーには、クライアントからリクエストが来た順番に処理する「反復サーバー」とイベントを切り替えながらリクエストを処理する「並行サーバー」がある。今回は前者の反復サーバーを実装する。

新規プロジェクトとソースコードを用意

 まず新しいプロジェクトを作成しよう。cargo newコマンドを実行すると、新しいプロジェクトを作成できる。

$ cargo new http-server

 http-serverディレクトリーの下は次のような構造になっているはずだ。

.
├── Cargo.toml
└── src
   └── main.rs

 では反復サーバーを実装してみよう。main.rsの内容を次のソースコードに書き換える。

use std::{
    fs::read_to_string,
    io::{Read, Write},
    net::{TcpListener, TcpStream},
    thread,
};

fn start() -> std::io::Result<()> {
    let listener = TcpListener::bind("0.0.0.0:9999")?;
    while let Ok((stream, _)) = listener.accept() {
        thread::spawn(|| handler(stream));
    }
    Ok(())
}

fn handler(mut stream: TcpStream) -> std::io::Result<()> {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer)?;

    let get = b"GET / HTTP/1.1\r\n";

    let response = if buffer.starts_with(get) {
        let status_line = "HTTP/1.1 200 OK";
        let html = read_to_string("index.html")?;
        let http_header = format!(
            "Content-Length: {}\r\nContent-Type: text/html;charset=UTF-8",
            html.len()
        );
        format!("{}\r\n{}\r\n\r\n{}", status_line, http_header, html)
    } else {
        "HTTP/1.1 404 NotFound\r\n\r\n".to_string()
    };

    stream.write_all(response.as_bytes())?;
    stream.flush()
}

fn main() -> std::io::Result<()> {
    start()
}