나는 C로 작은 HTTP 서버를 만들어 웹이 실제로 어떻게 작동하는지 이해했다

발행: (2026년 1월 11일 오전 05:27 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

What I Wanted (and What I Didn’t)

이 프로젝트는 절대 프로덕션 서버를 만드는 것이 목적이 아니었습니다.
Nginx와 경쟁하려는 것도 아니었고, 아주 기본적인 질문들에 대한 답만 원했습니다:

  • HTTP 요청은 실제로 어떻게 생겼을까?
  • 서버는 어떤 파일을 반환할지 어떻게 결정할까?
  • accept()와 브라우저가 페이지를 렌더링하기 사이에 무슨 일이 일어날까?

그게 전부였습니다.

What This Server Actually Does

정확히 이 정도만 합니다 — 더도 덜도 아니죠:

  • 포트 8080에서 리스닝
  • GET 요청만 처리
  • 정적 파일(HTML, 텍스트, 이미지) 제공
  • POSIX 스레드 사용(클라이언트 1명당 1스레드)
  • 올바른 Content-Type 헤더 전송
  • 파일이 없을 경우 간단한 404 반환

한 번에 이해할 수 있을 정도로 작습니다.

Code Structure (Because One File Is a Nightmare)

모든 코드를 main.c에 몰아넣고 싶지는 않아서 파일을 나눴습니다:

  • main.c → 소켓 설정, bind, listen, accept 루프
  • request.c → 요청을 읽고 클라이언트를 처리
  • http.c → HTTP 응답을 생성
  • utils.c → MIME 타입 및 URL 디코딩

특별한 트릭은 없습니다. 책임을 분리했을 뿐이죠. 이 덕분에 디버깅이 훨씬 수월해졌습니다.

The First “Oh Damn” Moment

처음으로 원시 HTTP 요청을 터미널에 출력했을 때, 드디어 깨달았습니다:

GET /index.html HTTP/1.1
Host: localhost:8080

그게 전부였습니다. 객체가 없죠. 그 순간 HTTP가 더 이상 신비롭게 느껴지지 않았습니다.

Parsing Without Overthinking

전체 HTTP 파서를 만들지는 않았습니다. 작은 정규식을 사용해 GET / 뒤의 파일 경로를 추출하고, 디코딩한 뒤 바로 진행했습니다.

취약한가요? 네. 과도한 설계는 이 프로젝트의 핵심 목적을 무너뜨렸을 겁니다.

Building the Response Manually

또 하나 간과하기 쉬운 사실: 유효한 응답은 문자 그대로:

status line
headers
(empty line)
body

이 흐름을 하드코딩하니 모든 것이 이해됐습니다. 파일을 찾지 못했을 때는 간단한 404를 반환했습니다.

MIME Types: Small Detail, Big Lesson

한때 HTML은 잘 보였지만 이미지가 안 보였던 적이 있습니다. 브라우저가 Content-Type을 정말 신경 쓴다는 사실을 깨달았습니다. 그래서 작은 확장자 → MIME 매핑을 추가했죠:

  • .htmltext/html
  • .jpgimage/jpeg
  • .pngimage/png

그때부터 모든 것이 정상적으로 렌더링되었습니다. 이 사소한 버그가 수십 개의 블로그 포스트보다 더 큰 교훈을 주었습니다.

Why C?

C는 아무것도 숨기지 않기 때문입니다. 동작한다면, 여러분이 직접 만들었기 때문이죠. C로 구현하면서:

  • 소켓을 제대로 이해하게 됨
  • 메모리를 신중히 관리하게 됨
  • 추상화가 아닌 실제 시스템 콜을 읽게 됨

그리고 솔직히 현대 프레임워크에 대한 감탄이 더 커졌습니다.

What This Server Is Bad At (On Purpose)

분명히 해야 할 점 — 이 서버는 다음 기능을 지원하지 않습니다:

  • POST 요청
  • HTTPS
  • Keep‑alive 연결
  • 보안
  • 실제 트래픽 처리

그리고 괜찮습니다. 학습용 프로젝트였고, 스타트업이 아니니까요.

Final Thoughts

프레임워크 없이 서버를 만든 적이 없다면, 한 번 시도해 보길 권합니다. 도구를 대체하려는 목적이 아니라, 완성하려는 압박도 없습니다. 저에게 이 프로젝트는 HTTP에 대한 많은 혼란을 해소해 주었고, 그 자체만으로도 충분히 가치 있었습니다.

Thanks for reading 🙌

Back to Blog

관련 글

더 보기 »

TCP는 메시지가 무엇인지 모른다

HTTP를 다룰 때 나는 마음 한구석에 조용한 가정을 가지고 있었다: > 내가 하나를 보내면, 반대쪽도 하나를 받는다. 그것은 당연해 보였다. Al...

Todo 앱

소개 첫 번째 논리 중심 프로젝트인 Counters를 완료한 후, 나는 UI를 개선하는 것이 아니라 복잡성의 다음 자연스러운 단계로 나아가고 싶었다 — ...