네트워크 프로그래밍과 HTTP 프로토콜에 대한 깊은 이해를 바탕으로 웹 서버의 핵심 기능을 C++로 구현했습니다.
이 프로젝트의 핵심 도전은 Node.js나 Spring 같은 고수준 프레임워크의 도움 없이, 순수 C++와 시스템 콜(System Call)만으로 HTTP/1.1 웹 서버를 구현하는 것이었습니다. 이를 위해서는 네트워크 소켓 프로그래밍, HTTP 프로토콜의 상세 명세, 그리고 다수의 클라이언트 요청을 효율적으로 처리하기 위한 비동기(Asynchronous) I/O 모델에 대한 깊은 이해가 필수적이었습니다.
Nginx와 같은 고성능 웹 서버의 핵심 원리인 이벤트 기반 아키텍처를 구현하기 위해 BSD 계열 OS에서 고성능을 보장하는 `kqueue`를 이벤트 통지 메커니즘으로 채택했습니다. 이를 통해 단일 스레드(또는 소수의 스레드)만으로 수많은 클라이언트 연결을 동시에 관리하고, I/O 작업이 발생할 때만 CPU 자원을 사용하도록 하여 서버의 효율성을 극대화했습니다.
[그림 8] kqueue 기반 웹 서버 동작 아키텍처
클라이언트의 모든 연결과 데이터 수신/송신 요청은 `kqueue`에 이벤트로 등록됩니다. 서버는 무한 루프를 돌며 `kevent()` 함수를 통해 발생한 이벤트들을 감지하고, 각 이벤트에 맞는 핸들러(연결 수락, 데이터 읽기/쓰기)를 호출하여 비동기적으로 요청을 처리합니다. 동적 콘텐츠를 위해 CGI(Common Gateway Interface)를 구현하여 Python 스크립트를 실행하고 그 결과를 클라이언트에 전달하는 기능도 포함했습니다.
// 예시: kqueue를 활용한 메인 이벤트 루프#include <sys/event.h>void server_loop(int server_socket) {int kq = kqueue(); // kqueue 인스턴스 생성struct kevent change_list[1];struct kevent event_list[MAX_EVENTS];// 서버 소켓의 읽기 이벤트를 kqueue에 등록EV_SET(&change_list[0], server_socket, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);kevent(kq, change_list, 1, NULL, 0, NULL);while (true) {// 이벤트가 발생할 때까지 대기int nev = kevent(kq, NULL, 0, event_list, MAX_EVENTS, NULL);if (nev == -1) { /* 에러 처리 */ }for (int i = 0; i < nev; ++i) {if (event_list[i].ident == server_socket) {// 새로운 클라이언트 연결 수락accept_new_connection(kq, server_socket);} else {// 기존 클라이언트의 I/O 이벤트 처리 (읽기/쓰기)handle_client_event(event_list[i]);}}}}
HTTP/1.1 명세의 핵심 기능(GET, POST, DELETE)을 준수하는 정적 웹 서버를 성공적으로 구현했습니다. 이 프로젝트를 통해 웹 프레임워크가 내부적으로 어떻게 동작하는지에 대한 근본적인 이해를 얻었고, 시스템 레벨의 성능 최적화에 대한 깊이 있는 시야를 확보했습니다. 이 경험은 다른 고수준 언어나 프레임워크를 사용할 때도 기술의 본질을 이해하고 더 나은 아키텍처를 설계하는 데 강력한 기반이 되었습니다.