# 15차 러스트 스터디 ## 담당 - 발표: 이명수 님 - 서기: 이재현 님 ## 마지막 프로젝트: 멀티 스레드 웹 서버 만들기 - 싱글 스레드로 웹 서버 만드는 프로젝트 ### 20.1. 싱글 스레드 웹서버 - TCP 커넥션 ``` rust use std::net::TcpListener; fn main() { let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); for stream in listener.incoming() { let stream = stream.unwrap(); println!("Connection established!"); } } ``` #### 요청 데이터 읽기 ``` rust use std::io::prelude::*; use std::net::TcpStream; use std::net::TcpListener; fn main() { let listener = TcpListener::bind("127.0.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; 512]; stream.read(&mut buffer).unwrap(); println!("Request: {}", String::from_utf8_lossy(&buffer[..])); } ``` #### 응답 작성하기 ``` rust fn handle_connection(mut stream: TcpStream) { let mut buffer = [0; 512]; stream.read(&mut buffer).unwrap(); let response = "HTTP/1.1 200 OK\r\n\r\n"; stream.write(response.as_bytes()).unwrap(); stream.flush().unwrap(); } ``` #### 실제 html로 응답하기 - 실제 html 파일을 생성하고 해당 파일 내용을 읽어서 응답할 수 있다. ```htmlembedded <html lang="en"> <head> <meta charset="utf-8"> <title>Hello!</title> </head> <body> <h1>Hello!</h1> <p>Hi from Rust</p> </body> </html> ``` ``` rust use std::fs::File; fn handle_connection(mut stream: TcpStream) { let mut buffer = [0; 512]; stream.read(&mut buffer).unwrap(); let mut file = File::open("hello.html").unwrap(); let mut contents = String::new(); file.read_to_string(&mut contents).unwrap(); let response = format!( "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", contents.len(), contents ); stream.write(response.as_bytes()).unwrap(); stream.flush().unwrap(); } ``` ### 20.2. 싱글 스레드 서버를 멀티스레드 서버로 바꾸기 #### 현재 서버에서 느린 요청을 시뮬레이팅하기 - 싱글 스레드인 경우 하나의 느린 작업이 있을 때 다른 연결에 대한 처리를 할 수 없다. - 따라서 멀티스레드로 작업할 수 있게 변경해야한다. #### 스레드 풀을 이용한 처리량 증진 - 각각의 요청이 들어올때마다 새 스레드를 생성한다면 많은 요청이 들어올 때 서버의 모든 리소스를 사용하게 될 것이다. - 따라서 미리 스레드를 만들어두고 요청이 들어올 때 각 스레드에 요청을 전달해 작업하도록 해야한다. - 이렇게 미리 만들어 둔 스레드의 모음을 스레드 풀이라고 한다. ### 20.3. 우아한 종료와 정리 - 20.2 에서 구현한 코드는 스레드에게 종료 메시지 전달 없이 서버를 강제 종료해 작업 중이던 스레드가 강제로 종료된다. - 이를 해결해야한다. #### ThreadPool 에 Drop 트레잇 구현하기 - ThreadPool에 Drop 트레잇을 구현해 프로그램이 종료되면서 ThreadPool이 Drop 될 때 정리 해주는 코드를 삽입할 수 있다. #### 스레드가 작업 리스닝을 중지하도록 신호하기 - Message 구조체를 생성 후 Drop 트레잇이 호출되면 Terminate 메시지를 전달한다. #### [전체 소스코드](https://github.com/JannLee/rust-study/tree/main/Jaehyeon/Chapter20/hello) ## 회고 - 이지한: - 김기덕: 마지막 과제하면서 예전에 파일럿 프로젝트하던게 떠올랐네요. 다 끝내서 좋습니다! - 유병조: 러스트가 인기가 많다고 해서 어떤 언어인지 궁금했는데 배워보니까 재미있네요~ - 이명수: 드디어 끝났네요. ㅜㅜ 잠깐 머리 비우고 다시 돌아오는 걸로 ~~~ ㅎㅎ - 이재현: 재밌던 부분도 있었고 모르지만 지나온 부분도 있지만 끝까지 다 해서 뿌듯하네요! - 정연집: - 허신: 아직 모든 내용을 이해하진 못했지만 rust라는 언어에 대해 전반적으로 알게 돼서 유익했어요