🦁

初投稿 Rustでシングルスレッドサーバーを立ち上げる

2021/12/22に公開

はじめに

初投稿になります。
2021/3から自社開発企業で実務にて主にGo、svelteを扱っております。
3児の親で家事、育児ありあまり時間がありませんが隙間時間等活用して活動しています。

今回から独学ですがRustを勉強して記録として残そうと思い投稿することになりました。
内容が薄いかもしれませんが多めに見ていただけると幸いです。

まず最初の目標は

  • Rustを使用してTODOアプリの作成
    としています。

シングルスレッドサーバーを立ち上げる(ドキュメントから抜粋)

まずコードですがこちら

main.rs

use std::fs::File;
use std::io::prelude::*;
use std::net::TcpStream;
use std::net::TcpListener;


fn main() {
    let listener = TcpListener::bind("127.0.1:7878").unwrap();

    for stream in listener.incoming() {
        let stream = stream.unwrap();

        handle_connection(stream);
    }
}


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

    stream.read(&mut buffer).unwrap();

    let mut file = File::open("index.html").unwrap();

    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();

    let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents);

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

何をしたのか

結果から言うと
webサーバーを立ち上げて
http://127.0.0.1:7878
にアクセスしたらindex.htmlを返す単純なコードになります。

コードの解説(順を追って書いています)

index.htmlについて

これは好きに記述しました。

使用するモジュール(後述に内容記述している箇所もあります)

std::io::preludeをスコープに導入して、ストリームから読み書きさせてくれる特定のトレイトにアクセスできるようにしています。
WebサーバーはTCP接続とのことで標準ライブラリのstd::netというモジュールを使用しています。

use std::fs::File;
use std::io::prelude::*;
use std::net::TcpStream;
use std::net::TcpListener;

main関数について

TCPストリームを受信するため127.0.0.1:7878というアドレスを設定しています。
unwrap()はエラーが起きればプログラムを停止させるメソッドです。
次のfor文でリクエストが来るのを待ち、handle_connection関数でブラウザからのリクエスト処理します。
incomingメソッドは単独のストリームがクライアント・サーバー間の開かれた接続を表します。
引数のstreamは、上記のTcpstreamインスタンスが内部で返すデータを追いかけているようで、内部のデータが変化してしまう可能性があるようです。

fn main() {
    let listener = TcpListener::bind("127.0.1:7878").unwrap();

    for stream in listener.incoming() {
        let stream = stream.unwrap();

        handle_connection(stream);
    }
}

handle_connection関数について

上記use部分の先頭に行の標準ライブラリのFileをスコープに導入しました。
読み取ったデータを保持するbufferを宣言し、今回は1024bytesに設定しました(今後の管理はもっと複雑になるようです、、、)。
このバッファーをstream.readに渡し、 これがTcpStreamからバイトを読み取ってバッファーに置きます。
宣言したcontentsにファイルを開き、中身を読み込み代入します。
response変数を定義して、format!でファイルの中身を成功したレスポンスの本体として追記しています。
それに対してas_bytesを呼び出し、文字列データをバイトに変換します。streamのwriteメソッドは、 &[u8]を取り、接続に直接そのバイトを送信するようです。

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

    stream.read(&mut buffer).unwrap();

    let mut file = File::open("index.html").unwrap();

    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();

    let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents);

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

以上でサーバーを立ち上げindex.htmlを返すコードになります。

Discussion