교재 실습/자바 웹 프로그래밍 Next Step

3.4.2 실습 환경 세팅 및 소스코드 분석

Jint 2025. 1. 29. 09:31

실습으로 진행할 HTTP 웹 서버는 로컬 개발 환경을 세팅한 https://github.com/slipp/web-application-server 저장소의 master 브랜치에서 시작하면 된다. webserver.WebServer를 실행한 후 브라우저에서 http://localhost:8080 으로 접근했을 때 "Hello World" 메시지가 출력되면 실습할 수 있는 준비가 끝났다.

실습으로 진행할 HTTP 웹 서버의 핵심이 되는 코드는 webserver 패키지의 WebServer와 RequestHandler 클래스이다. WebServer 클래스는 웹 서버를 시작하고, 사용자의 요청이 있을 때까지 대기 상태에 있다가 사용자의 요청이 있을 경우 요청을 RequestHandler 클래스에 위임하는 역할을 한다.

 

- WebServer.java

package webserver;

import java.net.ServerSocket;
import java.net.Socket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class WebServer {
    private static final Logger log = LoggerFactory.getLogger(WebServer.class);
    private static final int DEFAULT_PORT = 8080;

    public static void main(String args[]) throws Exception {
        int port = 0;
        if (args == null || args.length == 0) {
            port = DEFAULT_PORT;
        } else {
            port = Integer.parseInt(args[0]);
        }

        // 서버소켓을 생성한다. 웹서버는 기본적으로 8080번 포트를 사용한다.

        try (ServerSocket listenSocket = new ServerSocket(port)) {
            log.info("Web Application Server started {} port.", port);

            // 클라이언트가 연결될때까지 대기한다.
            Socket connection;
            while ((connection = listenSocket.accept()) != null) {
                RequestHandler requestHandler = new RequestHandler(connection);
                requestHandler.start();
            }
        }
    }
}

 

사용자 요청이 발생할 때까지 대기 상태에 있도록 지원하는 역할은 자바에 포함되어 있는 ServerSocket 클래스가 담당한다. WebServer 클래스는 ServerSocket에 사용자 요청이 발생하는 순간 클라이언트와 연결을 담당하는 Socket을 RequestHandler 에 전달하면서 새로운 스레드를 실행하는 방식으로 멀티스레드 프로그래밍을 지원하고 있다.

RequestHandler 클래스는 Thread를 상속하고 있으며, 사용자의 요청에 대한 처리와 응답에 대한 처리를 담당하는 가장 중심이 되는 클래스다.

 

- RequestHandler.java

package webserver;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RequestHandler extends Thread {
    private static final Logger log = LoggerFactory.getLogger(RequestHandler.class);

    private Socket connection;

    public RequestHandler(Socket connectionSocket) {
        this.connection = connectionSocket;
    }

    public void run() {
        log.debug("New Client Connect! Connected IP : {}, Port : {}", connection.getInetAddress(),
                connection.getPort());

        try (InputStream in = connection.getInputStream(); OutputStream out = connection.getOutputStream()) {
            // TODO 사용자 요청에 대한 처리는 이 곳에 구현하면 된다.
            DataOutputStream dos = new DataOutputStream(out);
            byte[] body = "Hello World".getBytes();
            response200Header(dos, body.length);
            responseBody(dos, body);
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    private void response200Header(DataOutputStream dos, int lengthOfBodyContent) {
        try {
            dos.writeBytes("HTTP/1.1 200 OK \r\n");
            dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n");
            dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
            dos.writeBytes("\r\n");
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    private void responseBody(DataOutputStream dos, byte[] body) {
        try {
            dos.write(body, 0, body.length);
            dos.flush();
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }
}

 

앞으로 진행할 모든 실습은 RequestHandler 클래스의 run() 메서드에서 구현할 수 있다. 단, run() 메서드의 복잡도가 증가하는 경우 새로운 클래스, 메서드로 분리하는 방식으로 리팩토링을 하면서 실습을 진행하면 된다. run() 메서드에서 InputStream은 클라이언트(웹 브라우저)에서 서버로 요청을 보낼 때 전달되는 데이터, OutputStream은 서버에서 클라이언트에 응답을 보낼 때 전달되는 데이터를 담당하는 스트림이다. 스트림을 이해할 때 웹 서버 입장에서 입력되는 데이터( InputStream)와 출력되는 데이터(OutputStream)를 이해하면 좀 더 쉽게 이해할 수 있다.

 

프로그래밍을 할 때 좋은 습관 중의 하나는 프로그래밍 실행 중 발생하는 로그 메시지를 주의 깊게 살펴보는 것이다. 로그 메시지는 프로그래밍이 정상적으로 실행되고 있는지의 여부를 판단할 수 있는 정보를 제공해 준다. 이번 실습을 하면서도 로그로 출력되는 메시지를 눈여겨 본다. 로그 메시지를 통해 새로운 지식을 학습할 수 있는 기회도 된다. 로그 메시지를 적절하게 출력하도록 구현하는 것 또한 연습이 필요한 부분이다. 이 실습을 진행하면서 로그 메시지를 출력하는 연습도 같이 할 수 있다.

 


참고링크1 : https://kadosholy.tistory.com/121

 

[Java] 자바 - Thread란? 스레드 개념 및 사용방법

자바 - Thread란? 스레드 개념 및 사용방법 자바에서 여러가지 일을 동시에 처리하기 위해 사용되는 스레드(Thread)에 대해서 알아보도록 하겠습니다. 목차 프로세스와 스레드 (Process vs Thread) 스레드

kadosholy.tistory.com

void run( ) : 스레드의 실행코드가 작성되는 메소드로 사용자는 run() 메소드를 오버라이드 하여 사용해야 합니다.
void start( ) : 스레드가 시작되도록 요청하는 메소드로 JVM은 해당 스레드의 run() 메소드를 호출합니다. 

참고링크2 : https://hianna.tistory.com/602

 

[Java] 줄바꿈 하기 (\n, \r, \r\n 의 차이)

Java에서 문자열의 줄바꿈을 표현할 때 주로 아래와 같은 escape 문자를 사용합니다. \n \r \r\n 그렇다면 위 3가지 escape 문자의 차이점은 무엇일까요? 세가지 표현 모두 줄바꿈을 나타내지만, 시스템

hianna.tistory.com

세가지 표현 모두 줄바꿈을 나타내지만, 시스템에 따라서 사용하는 개행문자가 다릅니다.
\n - unix
\r - mac
\r\n - windows


참고도서 : https://roadbook.co.kr/169

 

[신간안내] 자바 웹 프로그래밍 Next Step

● 저자: 박재성 ● 페이지: 480 ● 판형: 사륙배변형(172*225) ● 도수: 1도 ● 정가: 30,000원 ● 발행일: 2016년 9월 19일 ● ISBN: 978-89-97924-24-0 93000 [강컴] [교보] [반디] [알라딘] [예스24] [인터파크] [샘

roadbook.co.kr