pu369com

Building a Concurrent Web Server with Async Rust

 

src/main.rs

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

fn main() {
    // Listen for incoming TCP connections on localhost port 7878
    let listener = TcpListener::bind("localhost:7878").unwrap();

    // Block forever, handling each request that arrives at this IP address
    for stream in listener.incoming() {
        let stream = stream.unwrap();

        handle_connection(stream);
    }
}

fn handle_connection(mut stream: TcpStream) {
    // Read the first 1024 bytes of data from the stream
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();

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

    // Respond with greetings or a 404,
    // depending on the data in the request
    let (status_line, filename) = if buffer.starts_with(get) {
        ("HTTP/1.1 200 OK\r\n\r\n", "hello.html")
    } else {
        ("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html")
    };
    let contents = fs::read_to_string(filename).unwrap();

    // Write response back to the stream,
    // and flush the stream to ensure the response is sent back to the client
    let response = format!("{}{}", status_line, contents);
    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}

hello.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Hello!</title>
  </head>
  <body>
    <h1>Hello!</h1>
    <p>Hi from Rust</p>
  </body>
</html>

404.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Hello!</title>
  </head>
  <body>
    <h1>Oops!</h1>
    <p>Sorry, I don't know what you're asking for.</p>
  </body>
</html>

 

注意hello.html和404.html与生成的EXE文件放在同一目录中,访问  http://127.0.0.1:7878 或 http://localhost:7878

参考:https://rust-lang.github.io/async-book/09_example/00_intro.html

 

补充:后来发现上面的不行,客户端浏览器关闭后就无法重新访问了,于是参照官方例子:https://doc.rust-lang.org/book/ch20-02-multithreaded.html

将main.rs改成:

use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::thread;
fn main() {   
    let listener = TcpListener::bind("localhost:7878").unwrap();      
   /* match listener.accept() {
         Ok((_socket, addr)) => println!("new client: {:?}", addr),
         Err(e) => println!("couldn't get client: {:?}", e),
     }
     */
     for stream in listener.incoming() {
        let stream = stream.unwrap();       
        thread::spawn(|| {
            handle_connection(stream);
        });   
    
}
}


fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 1024];    
    stream.read(&mut buffer).unwrap();   
    let bufctx = String::from_utf8_lossy(&buffer).to_string();
    println!("{}",bufctx);
    let status_line = {"HTTP/1.1 200 OK\r\n\r\n" }; 
    stream.write(status_line.as_bytes()).unwrap();
    let body_ctx = {"<html><form action=\"\" method=\"post\">
    <input type=\"text\" name=\"text1\" />
    <input type=\"submit\" />
    </form></html>" }; 
    stream.write(body_ctx.as_bytes()).unwrap();
    stream.flush().unwrap();   
     
}

 然而,服务器过一会儿又panic,原来是没有写Content-Length ,或是thread::sleep?

改为:

use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::thread;
use std::time::Duration;
fn main() {   
    let listener = TcpListener::bind("localhost:7878").unwrap();   
     for stream in listener.incoming() {
        let stream = stream.unwrap();       
        thread::spawn(|| {
            handle_connection(stream);
        });   
    
}
}
fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 1024];    
    stream.read(&mut buffer).unwrap();   
    let bufctx = String::from_utf8_lossy(&buffer).to_string();
    println!("{}",bufctx);
    let sleep = b"GET /sleep HTTP/1.1\r\n";
    let status_line =if buffer.starts_with(sleep) {
        thread::sleep(Duration::from_secs(5));
        "HTTP/1.1 200 OK"
    } else {
        "HTTP/1.1 200 OK"
    };
    let contents = "<html><form action=\"\" method=\"post\">
    <input type=\"text\" name=\"text1\" />
    <input type=\"submit\" />
    </form></html>";
    let response = format!(
        "{}\r\nContent-Length: {}\r\n\r\n{}",
        status_line,
        contents.len(),
        contents
    );
    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();     
}

在局域网中测试用TcpListener::bind("localhost:7878") 或 TcpListener::bind("127.0.0.1:7878") 都不行,表现为用局域网本机IP访问不通。

改为TcpListener::bind("0.0.0.0:7878") 才行。

posted on 2021-09-13 16:45  pu369com  阅读(42)  评论(0编辑  收藏  举报

导航