Skip to content

byunghak/rust-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust HTTP Server

외부 크레이트 없이 Rust 표준 라이브러리만으로 구현한 멀티스레드 HTTP 서버다. Rust Book Chapter 20을 기반으로, ownership과 concurrency를 네트워크 프로그래밍으로 직접 체험하기 위해 만들었다.

프로젝트 소개 (About)

TCP 소켓 바인딩부터 HTTP 응답 생성, thread pool을 통한 동시 요청 처리까지 전부 std만으로 구현했다. 의존성이 없으므로 Rust가 제공하는 저수준 primitive — TcpListener, mpsc, Arc<Mutex<T>> — 를 직접 다루는 구조다.

기술 스택: Rust 2021 edition, zero dependency

프로젝트 구조 (Architecture)

src/
├── bin/
│   └── main.rs          # 진입점 — Http 인스턴스 생성 후 listen 호출
├── http/
│   └── mod.rs           # TCP 바인딩, HTTP 요청 파싱, 라우팅, 응답 생성
├── pool/
│   ├── mod.rs           # Generic thread pool — mpsc channel 기반 작업 분배
│   └── worker.rs        # Worker thread — 작업 수신 루프 + 종료 제어
└── lib.rs               # 모듈 공개

모듈별 역할

httpTcpListener로 연결을 수락하고, 요청 바이트를 읽어 라우팅한 뒤 정적 파일을 응답으로 보낸다. 라우팅은 바이트 배열의 prefix 매칭으로 처리한다.

poolmpsc::channel의 sender/receiver 쌍으로 작업을 분배한다. receiver를 Arc<Mutex<_>>로 감싸서 여러 worker가 공유한다. Drop 구현으로 Terminate 메시지를 보내고 모든 thread를 join하는 graceful shutdown을 수행한다.

worker — 무한 루프에서 receiver를 잠그고 메시지를 꺼낸다. Message::Job이면 클로저를 실행하고, Message::Terminate면 루프를 빠져나온다.

요청 흐름

Client → TcpListener::incoming()
       → Pool::execute(closure)
       → mpsc::Sender → channel → Arc<Mutex<Receiver>>
       → Worker::work() — lock, recv, 실행
       → Http::handle_conn() — 파싱, 라우팅, 파일 읽기, 응답 전송

실행 방법 (Getting Started)

cargo run

127.0.0.1:5500에서 서버가 시작된다.

라우트 동작
GET / index.html 반환
GET /sleep 5초 대기 후 index.html 반환
그 외 404.html 반환

현재 2개 요청을 처리한 뒤 종료된다 — incoming().take(2) 제한이 걸려 있다.

학습 포인트 (Learnings)

Arc<Mutex<Receiver<T>>>mpsc::ReceiverClone을 구현하지 않는다. 여러 worker가 하나의 receiver를 공유하려면 Arc로 소유권을 공유하고 Mutex로 접근을 직렬화해야 한다. 이 패턴이 Rust에서 "공유 상태 동시성"의 기본 형태다.

Drop trait으로 graceful shutdownPool이 스코프를 벗어날 때 Drop::drop이 호출된다. 여기서 worker 수만큼 Terminate 메시지를 보내고, 각 thread를 join한다. 종료 메시지를 먼저 전부 보낸 뒤 join하는 순서가 중요하다 — 순서가 섞이면 deadlock이 발생할 수 있다.

Message enum으로 종료 제어 — channel에 클로저만 보내면 worker를 멈출 방법이 없다. Message::Job(T) / Message::Terminate enum을 정의해서, 작업과 종료 신호를 같은 channel로 전달한다.

Generic trait bound Pool<T: FnOnce() + Send + 'static> — pool이 받는 클로저의 조건을 타입 수준에서 강제한다. FnOnce는 한 번만 실행, Send는 thread 간 전송 가능, 'static은 thread보다 오래 살아야 함을 보장한다.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors