이 프로젝트는 Java의 기본 java.net.Socket API만을 사용하여 처음부터 직접 TCP 서버와 HTTP 서버를 구현하는 과정을 담고 있습니다. 외부 라이브러리 없이 네트워크 통신의 가장 기본적인 원리를 이해하고, 저수준(low-level)에서 프로토콜을 어떻게 처리하는지 학습하는 것을 목표로 합니다.
프로젝트의 메인 진입점은 com.astordev.WebApplication 클래스입니다. 이 클래스 내부의 Mode 열거형 변수를 수정하여 TCP 서버 또는 HTTP 서버를 선택적으로 실행할 수 있습니다.
class WebApplication {
// 이 부분을 Mode.TCP 또는 Mode.HTTP로 변경하여 실행
private final static Mode mode = Mode.HTTP;
public static void main(String[] args) {
Server server = null;
switch (mode) {
case HTTP -> { ... }
case TCP -> { ... }
}
server.start();
}
}프로젝트는 서버의 공통 인터페이스, TCP 서버 구현, HTTP 서버 구현 세 부분으로 나뉩니다. Server와 SocketHandler라는 공통 인터페이스를 통해 서버의 종류와 관계없이 일관된 구조로 클라이언트 연결을 처리하도록 설계되었습니다.
최상위 패키지는 서버와 소켓 핸들러의 역할을 정의하는 핵심 추상화를 제공합니다.
Server: 서버 애플리케이션의 추상화를 위한 인터페이스입니다.start()메서드를 통해 서버를 시작하는 기능을 정의합니다.TcpServer와HttpServer가 이 인터페이스를 구현합니다.SocketHandler: 클라이언트Socket연결 하나를 처리하는 로직을 정의하는 인터페이스입니다.handle(Socket socket)메서드는 특정 클라이언트와의 전체 통신 주기를 담당합니다.
이 패키지는 간단한 TCP 에코(echo) 서버와 클라이언트를 구현합니다. 클라이언트가 보낸 메시지를 콘솔에 출력하고, 미리 정해진 메시지를 클라이언트에게 다시 보내는 기본적인 소켓 통신을 보여줍니다.
TcpServer:Server인터페이스의 구현체입니다. 지정된 포트에서ServerSocket을 열고, 무한 루프를 돌며 클라이언트의 연결을 기다립니다. 새로운 연결이 수립될 때마다 해당Socket을 스레드 풀(ExecutorService)에 전달하여TcpSocketHandler가 병렬로 처리하도록 합니다.TcpSocketHandler:SocketHandler인터페이스의 구현체입니다. 클라이언트 소켓으로부터 데이터를 읽어 콘솔에 출력하고, "Hello, World!" 메시지를 클라이언트에게 전송하는 역할을 합니다. 클라이언트와의 연결이 끊어질 때까지 이 작업을 반복합니다.TcpClientApplication:TcpServer를 테스트하기 위한 간단한 콘솔 기반 TCP 클라이언트입니다. 서버에 연결한 후, 사용자가 콘솔에 입력한 메시지를 서버로 보내고 서버로부터 받은 응답을 화면에 출력합니다.
이 패키지는 기본적인 HTTP/1.1 프로토콜을 해석하고 응답할 수 있는 원시적인 웹 서버를 구현합니다. 요청 라인, 헤더, 바디를 파싱하고, 특정 URL 경로에 따라 다른 응답을 보내는 기능을 포함합니다.
HttpServer:TcpServer와 유사하게Server인터페이스를 구현합니다.ServerSocket을 통해 클라이언트 연결을 수락하고, 각 연결을 스레드 풀에 위임하여HttpSocketHandler가 처리하도록 합니다.HttpSocketHandler: HTTP 통신을 총괄하는 핵심 클래스입니다.Socket을 받아keep-alive연결을 관리하며, 타임아웃을 설정합니다. 소켓의InputStream을HttpRequest객체로 변환하고,OutputStream을 사용하여HttpResponse객체를 통해 응답을 보냅니다. 요청된HttpMethod와URI에 따라 등록된RequestProcessor를 찾아 실제 비즈니스 로직을 위임합니다.HttpRequest: 소켓의InputStream을 읽어 HTTP 요청을 파싱하는 클래스입니다. 요청 라인(e.g.,GET /hello HTTP/1.1), 헤더, 그리고Content-Length헤더가 있는 경우 요청 바디(body)를 읽어 객체 형태로 저장합니다.HttpResponse: HTTP 응답을 생성하는 클래스입니다. 상태 코드(e.g., 200, 404), 헤더, 응답 바디를 설정할 수 있습니다.flushBuffer()메서드가 호출되면, 설정된 정보들을 바탕으로 완전한 HTTP 응답 메시지를 포맷에 맞게OutputStream에 씁니다.RequestProcessor: 특정 HTTP 요청을 처리하는 비즈니스 로직(컨트롤러 역할)을 정의하는 인터페이스입니다.process(request, response)메서드를 통해 실제 작업을 수행합니다. (Strategy Pattern)HandlerKey:HttpMethod와URI경로를 조합하여RequestProcessor를 찾기 위한 맵(Map)의 키로 사용되는 객체입니다.HttpMethod:GET,POST등 표준 HTTP 메서드를 정의한 열거형(Enum)입니다.
http.presentation: 실제 요청을 처리하는RequestProcessor구현체들을 포함합니다.HelloWorldRequestProcessor:GET /hello요청을 처리하는 예제 구현체입니다. 응답 상태를 200으로 설정하고, "Hello, World!" 문자열을 응답 바디에 씁니다.
- [HttpServer] 클라이언트가 서버 포트로 TCP 연결을 시도하면,
ServerSocket이 연결을 수락하여 새로운Socket을 생성합니다. - [HttpServer -> HttpSocketHandler]
HttpServer는 생성된Socket을 스레드 풀의 스레드에게 할당하고,HttpSocketHandler의handle()메서드를 호출합니다. - [HttpSocketHandler -> HttpRequest]
HttpSocketHandler는 소켓의InputStream을HttpRequest생성자에 전달하여, 원시 바이트 스트림을 파싱하고HttpRequest객체를 만듭니다. - [HttpSocketHandler]
HttpRequest객체에서HttpMethod와URI를 가져와HandlerKey를 생성합니다. - [HttpSocketHandler -> RequestProcessor]
HandlerKey를 사용하여 미리 등록된RequestProcessor맵에서 적절한 핸들러(e.g.,HelloWorldRequestProcessor)를 찾습니다. - [RequestProcessor] 찾은 핸들러의
process()메서드를 호출하며,HttpRequest와HttpResponse객체를 인자로 전달합니다. 핸들러는HttpResponse객체에 상태 코드, 헤더, 응답 바디를 설정합니다. - [HttpSocketHandler -> HttpResponse] 핸들러의 실행이 끝나면,
HttpSocketHandler는HttpResponse의flushBuffer()메서드를 호출합니다. - [HttpResponse]
flushBuffer()메서드는 설정된 상태, 헤더, 바디 정보를 바탕으로 완전한 HTTP 응답 메시지를 만들어 소켓의OutputStream으로 전송합니다. - [HttpSocketHandler]
Connection: keep-alive헤더 여부에 따라 연결을 유지하거나 닫고, 스레드 처리를 종료합니다.