public class HttpServerV1 {
private final int port;
public HttpServerV1(int port) {
this.port = port;
}
public void start() throws IOException {
ServerSocket serverSocket = new ServerSocket(port);
log("서버 시작 port: " + port);
while (true) {
Socket socket = serverSocket.accept();
process(socket);
}
}
private void process(Socket socket) throws IOException {
try (
socket;
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), UTF_8));
PrintWriter writer = new PrintWriter(socket.getOutputStream(), false, UTF_8)
) {
String requestString = requestToString(reader);
if (requestString.contains("/favicon.ico")) {
log("favicon 요청");
return;
}
log("HTTP 요청 정보 출력");
System.out.println(requestString);
log("HTTP 응답 생성중...");
sleep(5000); // 서버 처리 시간
responseToClient(writer);
log("HTTP 응답 전달 완료");
}
}
private String requestToString(BufferedReader reader) throws IOException {
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (line.isEmpty()) {
break;
}
sb.append(line).append("\n");
}
return sb.toString();
}
private void responseToClient(PrintWriter writer) {
// 웹 브라우저에 전달하는 내용
String body = "<h1>Hello World</h1>";
int length = body.getBytes(UTF_8).length;
StringBuilder sb = new StringBuilder();
sb.append("HTTP/1.1 200 OK\r\n");
sb.append("Content-Type: text/html\r\n");
sb.append("Content-Length: ").append(length).append("\r\n");
sb.append("\r\n"); // header, body 구분 라인
sb.append(body);
log("HTTP 응답 정보 출력");
System.out.println(sb);
writer.println(sb);
writer.flush();
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
위 코드는 무슨 프로토콜 통신 방법인가?
- 앞선 코드는 HTTP 프로토콜로 통신을 하는 방법으로, HTTP의 규격을 맞추고 있음.
- 위 HTTP 메시지 구조로 맞게 코드를 구성해서 Buffer로 내보내고 있는 차이가 있음.
- 이 방식은 HTTP 프로토콜 규격에 맞춘 클라이언트와 통신하는 방식으로 예를 들어 웹브라우저와 통신할때는 이와 같은 방식으로 통신해야 함
- ServerSocket과 BufferedWriter를 통해서 단순 string data로만 통신한다면 이는 HTTP 통신이 아니고 TCP/IP 통신으로 예를 들어 단순 서버 클라이언트간 채팅을 주고받는다면 더욱 더 적합한 방법임.
앞선 코드를 톰캣+자바에서 제공해주는 서블릿 구조로 변경하면 무엇이 달라지는가?
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.println("Hello, World!");
}
}
- 앞선 코드는 서블릿을 직접 구현한 모습이라고 볼 수 있음.
- 따라서 HTTP와 관련된 모든 내용을 직접 구성을 해야 했지만 위 코드는 그러한 기본적인 구성을 알아서 해줌
- 또한, uri 맵핑, get, post에 대한 처리도 서블릿에서 기본적으로 모두 구현해 줌.
- 더 이상 ServerSocker, accpet() 이런 것에 대한 관리가 필요 없고 톰캣이 커넥션과 관련된 처리를 직접 해줌.
- 톰캣이 요청이 들어오면 그에 맞는 서블릿에 요청을 넘겨 줌.
WAS란?
- Web Application Server의 줄인말로 일반적으로 단순 Web Server는 이미지나 필요한 데이터를 제공해주는 서버인 반면에 WAS는 중간에 Application이 들어감.
- Application이 들어간다는 것은 웹 서버 역할에 추가로 프로그램 코드도 수행할 수 있다는 것을 의미
- 이는 HTTP 요청을 처리하면서 서블릿 구현체들이 하는 작업도 동시에 한다는 의미.