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") 才行。