zoukankan      html  css  js  c++  java
  • 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
    ";
    
        // 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
    
    ", "hello.html")
        } else {
            ("HTTP/1.1 404 NOT FOUND
    
    ", "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
    
    " }; 
        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
    ";
        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!(
            "{}
    Content-Length: {}
    
    {}",
            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") 才行。

  • 相关阅读:
    一款前端文件上传工具
    聊一聊最近找工作的感受
    神秘的计算机网络----(1)
    月下无限连?拒绝无休止switch!
    计算机网络---序
    验证码识别
    两数之和
    Sanic框架基础之解决CORS跨域
    Sanic框架进阶之实现异步缓存组件
    asyncio异步模块的21个协程编写实例
  • 原文地址:https://www.cnblogs.com/pu369/p/15263119.html
Copyright © 2011-2022 走看看