# 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라는 언어에 대해 전반적으로 알게 돼서 유익했어요