[Easy to understand series | rustlang language | zero-based | Getting Started | (26) | combat 3: Http Server]

[Easy to understand series | rustlang language | zero-based | Getting Started | (26) | combat 3: Http Server]

Project combat

Combat 3: Http Server

Let's develop our Http server today.

We first create a project directory with the command:

cargo new h_server

We now begin to write the following code in src / main.rs:

use std::net::TcpListener;

fn main() {
    //绑定IP和端口
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
     println!("server is up!");
    //从监听器得到网络IO流
    for stream in listener.incoming() {
        let stream = stream.unwrap();

        println!("Connection established!");
    }
}

Then we start our server directly, use the command to run it:

cargo run 

Print Console:

 Finished dev [unoptimized + debuginfo] target(s) in 0.87s
     Running `target\debug\h_server.exe`
server is up!

Description Server has been started.

We are now directly access the browser: http://127.0.0.1:7878/

Then, we go back to vscode console will print the following results:

......
Connection established!
Connection established!
Connection established!

Yes, our simple server developed good! Haha!

Here why print it three times?

Because when the browser to communicate with our servers, may for various reasons, will request retry several times.

Therefore, the server may receive requests several times.

First whether these details, in short, we have successfully connected to our server.

At this time, we directly: CTRL + c, exit the server.

That the browser sent me the request for information, what exactly is it?

Let's add some code, as follows:

use std::io::{Read, Write};
use std::net::{Shutdown, TcpListener, TcpStream};
use std::thread;
fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); //绑定监听端口
    println!("server is up!");
    for stream in listener.incoming() {
        let stream = stream.unwrap();
        println!("Connection established!");
        handle_connection(stream);
    }
}
//处理连接业务逻辑
fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 512]; //用一个长度为512的buffer

    stream.read(&mut buffer).unwrap(); //从Stream流中读取数据

    println!("Request: {}", String::from_utf8_lossy(&buffer[..])); //把buffer中的流数据转化成字符串
}

Also run the command:

cargo run 

Browser access:

Print server results:

Connection established!
Request: GET / HTTP/1.1
Host: 127.0.0.1:7878
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0
Connection established!
Request: GET / HTTP/1.1
Host: 127.0.0.1:7878
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0
Connection established!
Request: GET / HTTP/1.1
Host: 127.0.0.1:7878
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0

I will find here the browser sent me the information, some Key: information Value key-value pairs.

This information is, in fact, on behalf of the http request protocol.

In simple terms, http protocol, is the browser and the server Http dialogue communication standards, as we with the Chinese people with Chinese exchanges, as communicating in English with Americans.

Different protocols, like a different language.

About the http protocol, see: About HTTP protocol, one is enough

HTTP protocol detailed (really classic)

It will not be described here.

Let's add some code to respond to the request of http.

We return to the direct html page.

We create a new html file in the project directory: hello.html, which reads as follows:

<!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>

main.rs function code handle_connection, is updated to the following code:

//处理连接业务逻辑
fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 512]; //用一个长度为512的buffer

    stream.read(&mut buffer).unwrap(); //从Stream流中读取数据

    println!("Request: {}", String::from_utf8_lossy(&buffer[..])); //把buffer中的流数据转化成字符串
    let contents = fs::read_to_string("hello.html").unwrap();

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

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

Once again, we run the command:

cargo run 

Start the server.

Then use the browser to visit: http://127.0.0.1:7878/

We will get a page, which displays the contents:

Hello!

Hi from Rust

well.

We now check processing logic to increase the browser requests, handle_connection function code is updated as follows:

fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 512];
    stream.read(&mut buffer).unwrap();

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

    if buffer.starts_with(get) {
        let contents = fs::read_to_string("hello.html").unwrap();

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

        stream.write(response.as_bytes()).unwrap();
        stream.flush().unwrap();
    } else {
        // some other request
    }
}

Once again, we run the command:

cargo run 

Start the server.

Then use the browser to visit: http://127.0.0.1:7878/

Content with last time, but now we use: http://127.0.0.1:7878/a

The results show an error.

Because we do not handle error conditions.

Well, we now deal with it.

In the current project directory, create a html file: 404.html, the entire directory structure is as follows:

|-Cargo.toml
|-404.html
|-hello.html
|-src
    |- main.rs
|-tests
    |- test.rs

src / main.rs handle_connection function code is updated as follows:

fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 512];
    stream.read(&mut buffer).unwrap();

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

    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();

    let response = format!("{}{}", status_line, contents);

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

Once again, we run the command:

cargo run 

Start the server.

Then use the browser to visit: http://127.0.0.1:7878/

Content with last time, but now we use: http://127.0.0.1:7878/a

The results show that:

Oops!

Sorry, I don't know what you're asking for.

well! In line with our expectations.

We now have to create a good version of a simple http server.

Above, I hope useful to you.

如果遇到什么问题,欢迎加入:rust新手群,在这里我可以提供一些简单的帮助,加微信:360369487,注明:博客园+rust

Reference article:

https://doc.rust-lang.org/stable/book/ch20-01-single-threaded.html

https://riptutorial.com/rust/example/4404/a-simple-tcp-client-and-server-application--echo

Guess you like

Origin www.cnblogs.com/gyc567/p/12074343.html