# 네트워크 (6) - 웹과 HTTP
## 도메인

- 도메인은 인터넷 상에서 웹사이트를 찾아갈 수 있게 하는 주소의 일종이다. 이는 숫자로 이루어진 IP 주소를 사람이 이해하기 쉬운 텍스트 형태로 변환한 것이다.
- 도메인 이름 시스템 (DNS)이라는 서비스가 이 변환 작업을 수행한다. 사용자가 웹 브라우저에 도메인 이름을 입력하면, DNS 서버는 이를 해당 웹사이트의 IP 주소로 변환한다.
- 도메인 이름은 보통 "www.example.com"과 같이 구성되며, 이는 '서브도메인', '도메인 이름', 그리고 '상위 레벨 도메인'으로 구성된다. 위 예시에서 "www"는 서브도메인, "example"은 도메인 이름, 그리고 "com"은 상위 레벨 도메인이다.
- 도메인은 전 세계에서 유일해야 하며, 도메인을 관리하는 조직에서 일정 비용을 지불하고 등록해야 사용할 수 있다. 이 도메인 이름은 웹사이트 뿐 아니라 이메일 주소 등에도 사용된다.
## DNS (Domain Name System)

- DNS는 Domain Name System의 약자로, 사람이 읽을 수 있는 도메인 이름을 기계가 읽을 수 있는 IP 주소로 변환하는 시스템이다.
- DNS는 인터넷의 전화번호부와 같은 역할을 한다. 사용자가 웹 브라우저에 URL(예: `www.example.com`)을 입력하면, DNS 서버는 이 도메인 이름을 해당하는 IP 주소로 변환한다.
- 이 변환 과정을 'DNS 해석' 또는 'DNS 조회'라고 한다. DNS 서버는 이 정보를 캐싱하여, 동일한 요청에 대해 빠르게 응답할 수 있도록 한다.
- DNS는 계층적인 구조를 가지고 있어, 전 세계의 모든 도메인 이름과 IP 주소를 관리할 수 있다. 이 구조는 인터넷의 규모 확장에 따라 DNS 정보를 효과적으로 관리할 수 있게 한다.
- 또한 DNS는 도메인 이름을 이용해 부하 분산, 공격 방어 등의 다양한 기능을 제공한다. 이러한 이유로, DNS는 인터넷의 핵심 인프라 중 하나로 간주된다.

### 도메인의 계층 구조

- 도메인의 계층 구조는 인터넷상의 모든 컴퓨터를 명확하게 구분하기 위해 사용되며, DNS(Domain Name System)의 핵심 구성요소이다.
- 이 계층 구조는 '.'으로 구분된 여러 부분으로 이루어진 도메인 이름에서 볼 수 있다. 예를 들어, 'www.example.com'에서 'com'은 최상위 도메인(TLD), 'example'은 두 번째 레벨 도메인, 'www'는 세 번째 레벨 도메인이다.
- TLD : Top-level domain
- 최상위 도메인(TLD)은 도메인의 가장 오른쪽 부분으로, 일반적으로 사이트의 목적이나 위치를 나타낸다. 일반 TLD(gTLD)로는 '.com', '.org', '.net' 등이 있고, 국가 코드 TLD(ccTLD)로는 '.kr', '.jp', '.uk' 등이 있다.
- 두 번째 레벨 도메인은 각각의 사용자나 기관에 할당되며, 일반적으로 기관이나 서비스의 이름을 나타낸다.
- 세 번째 레벨 도메인은 특정 사이트나 서비스를 나타내는 경우가 많다. 일부 국가 코드 TLD에서는, 국가 내의 특정 조직이나 개체를 표시하는 데 3단계 도메인을 사용하기도 한다.
- 도메인 이름의 가장 왼쪽에 있는 부분을 호스트라고 하며 특정 서버나 서비스를 가리킨다. 'www'는 웹 서버를 가리키는 전통적인 예이다. 그러나 이런 규칙은 필수적이지 않으며, 많은 웹 사이트들이 'www' 없이도 접속이 가능하다.
- 이 계층적 구조는 전 세계의 모든 도메인을 유일하게 식별할 수 있게 하며, DNS 서버는 이 구조를 이용해 효율적으로 도메인 이름을 IP 주소로 변환한다.
### DNS 서버의 질의 과정

- DNS 질의 과정은 클라이언트가 도메인 이름에 해당하는 IP 주소를 찾기 위해 DNS 서버에 요청을 보내는 과정이다.
- 처음에 클라이언트는 설정된 로컬 DNS 서버에 도메인 이름에 대한 질의를 보낸다. 이 서버를 '재귀 DNS 서버'라고도 부른다.
- 로컬 DNS 서버는 이 질의에 대한 답을 알고 있으면 바로 응답한다. 이 정보는 일정 시간 동안 캐싱되어, 같은 질의에 대해 빠르게 응답할 수 있다.
- 만약 로컬 DNS 서버가 답을 모르면, 이 질의를 루트 DNS 서버로 전달한다. 루트 서버는 최상위 도메인에 대한 정보를 가지고 있으며, 이에 대한 답이나 다음 단계로 질의해야 할 DNS 서버에 대한 정보를 제공한다.
- 이후 로컬 DNS 서버는 제공된 정보를 바탕으로 다음 단계의 DNS 서버, 즉 TLD 서버에 질의를 보낸다. 이 과정이 반복되어 최종적으로 도메인 이름에 대한 IP 주소를 얻게 된다.
- 얻은 IP 주소는 로컬 DNS 서버에 캐싱되고, 이 정보는 원래의 클라이언트에 전달된다. 이제 클라이언트는 해당 IP 주소로 패킷을 보낼 수 있다.
- 이런 질의 과정을 통해 DNS는 전 세계의 모든 도메인 이름을 IP 주소로 변환할 수 있는 구조를 가지게 된다.
## World Wide Web

- 월드 와이드 웹(World Wide Web, WWW 또는 간단히 Web)은 인터넷에 연결된 컴퓨터를 통해 접근할 수 있는 정보 시스템이다.
- 웹의 발명자는 팀 버너스-리로, 1989년에 CERN에서 월드 와이드 웹을 제안했으며, 이후 1990년에 첫 웹 브라우저와 웹 서버를 만들었다.
- 팀 버너스 리가 웹을 개발하면서 정의한 세 가지 주요 기술은 HTML, URL, HTTP이다.
- 웹은 웹 페이지라는 문서들의 집합으로 구성되며, 각 웹 페이지는 URL(Uniform Resource Locator)이라는 고유한 주소를 가진다.
- 웹 페이지는 주로 HTML(Hypertext Markup Language)로 작성되며, CSS와 JavaScript 등의 기술과 함께 웹 사이트를 구성한다.
- 웹 페이지들은 하이퍼링크를 통해 서로 연결되어 있으며, 이를 통해 사용자는 정보를 탐색할 수 있다.
- 웹은 HTTP(Hypertext Transfer Protocol)라는 프로토콜을 기반으로 한다. HTTP는 웹 브라우저와 웹 서버 간의 통신 규약이다.

### HTML
- HTML(HyperText Markup Language)은 웹 페이지의 구조와 내용을 정의하는 마크업 언어다.
- 웹 브라우저는 HTML 문서를 해석하고, 사용자에게 그에 따른 웹페이지를 표시한다.
- HTML은 '태그'라 불리는 특별한 텍스트 요소를 사용하여, 웹 페이지의 다양한 부분(텍스트, 이미지, 비디오, 링크 등)을 표시하거나 구조화한다.
- HTML은 웹의 핵심 기술 중 하나로, CSS(Cascading Style Sheets)와 JavaScript와 함께 웹페이지의 구조, 스타일, 동작을 각각 담당한다

#### 마크업 언어
- 태그 등을 이용하여 문서나 데이터의 구조를 명기하는 언어의 한 가지이다.
- 태그는 원래 텍스트와는 별도로 원고의 교정부호와 주석을 표현하기 위한 것이었으나 용도가 점차 확장되어 문서의 구조를 표현하는 역할을 하게 되었다. 이러한 태그 방법의 체계를 마크업 언어라 한다.

### URL
- URL (Uniform Resource Locator)은 인터넷 상의 자원의 위치를 표시하는 주소 체계이다.
- URL은 통상적으로 웹 브라우저의 주소 창에 입력하여 웹 페이지를 불러올 때 사용되며, 전 세계 어떤 곳에 있는 웹 서버의 어떤 파일을 가리키든 간에 그 위치를 정확하게 표현할 수 있다.
- URL은 일반적으로 `프로토콜://도메인.탑레벨도메인/경로`의 형태를 가진다. 여기서 `프로토콜`은 리소스에 접근하는 데 사용되는 메소드 (예: http, https, ftp 등)를, `도메인`은 서버의 위치를, `탑레벨도메인`은 도메인의 카테고리를 나타낸다.
- `경로`는 서버에서의 자원의 위치를 나타내며, 이는 폴더와 파일 이름으로 이루어져 있다.
- URL은 웹 브라우저에서 웹 페이지에 액세스하거나, 하이퍼링크를 통해 다른 페이지로 이동할 때 사용된다. 또한 웹 페이지의 이미지, 동영상, 스타일시트, 스크립트 등의 자원에 대한 위치를 나타내는 데도 사용된다.
> 
>
> - URL에서 포트 번호를 명시하지 않은 경우, 웹 브라우저는 해당 프로토콜의 기본 포트를 사용하게 된다.
### HTTP
- HTTP (Hypertext Transfer Protocol)는 월드 와이드 웹에서 정보를 주고받는 프로토콜이다.
- HTTP는 클라이언트와 서버 간에 요청-응답 메시지 교환을 통해 동작하며, 주로 웹 브라우저와 웹 서버 사이에 HTML 문서와 같은 리소스를 전송하는 데 사용된다.
- HTTP는 비연결성과 무상태성을 가진다. 비연결성은 클라이언트와 서버가 한 번의 요청-응답을 완료한 후 즉시 연결을 끊는 특성을 의미하며, 무상태성은 서버가 클라이언트의 이전 요청에 대한 정보를 유지하지 않는 특성을 의미한다. 이러한 특성은 서버의 처리 능력을 향상시키지만, 연속된 요청 간의 정보 유지를 위해서는 별도의 기술이 필요하다.
- HTTP 메시지는 요청과 응답으로 이루어져 있으며, 각각은 시작 줄, 헤더, 본문의 세 부분으로 구성된다. 시작 줄은 요청 또는 응답의 종류를 나타내며, 헤더는 요청 또는 응답에 대한 메타데이터를 포함하고, 본문은 실제 전송되는 데이터를 포함한다.
- HTTP는 TCP/IP 위에서 동작하며, 기본적으로 TCP 포트 80을 사용한다. 보안을 위해 SSL/TLS와 함께 사용되는 경우 HTTPS라고 하며, 이 경우 TCP 포트 443을 사용한다.
#### HTTP 메시지의 구성

- HTTP 메시지는 요청과 응답 두 가지 유형이 있으며, 모두 비슷한 구조를 가지고 있다.
- HTTP 메시지는 시작 줄, 헤더, 본문의 세 부분으로 이루어져 있다.
- 시작 줄(Start Line): 시작 줄은 HTTP 메시지의 첫 번째 줄로, 요청 또는 응답의 성격을 정의한다. 요청 메시지의 경우, 이곳에는 HTTP 메소드(GET, POST 등), 요청 대상, 그리고 HTTP 버전이 포함된다. 응답 메시지의 경우, 이곳에는 HTTP 버전, 상태 코드, 그리고 상태 메시지가 포함된다.
- 헤더(Headers): 헤더는 요청 또는 응답에 대한 메타데이터를 포함한다. 헤더는 이름과 값의 쌍으로 이루어져 있으며, 여러 헤더가 존재할 수 있다. 헤더는 요청이나 응답의 본문 크기, 인코딩, 언어, 인증 정보 등을 설명한다.
- 본문(Body): 본문은 실제 전송하려는 데이터를 담는다. 본문은 모든 타입의 데이터를 포함할 수 있으며, 데이터의 유형은 'Content-Type' 헤더를 통해 명시된다. 본문은 필수적인 요소는 아니며, 특히 GET 요청과 같은 경우 본문이 없을 수도 있다.

##### HTTP 상태코드

- HTTP 상태 코드는 HTTP 응답 메시지에서 서버가 클라이언트에게 해당 요청의 처리 결과를 전달하는 데 사용되는 3자리 숫자 코드이다.
- 이 코드는 요청이 성공적으로 처리되었는지, 추가 정보가 필요한지, 오류가 발생했는지 등을 나타낸다.
- 상태 코드는 일반적으로 다음과 같이 5개의 클래스로 나뉜다.
- 1xx (정보): 요청을 받았으며, 프로세스를 계속 진행한다.
- 2xx (성공): 요청을 성공적으로 받았으며, 이해했고, 승인되었다.
- 3xx (리다이렉션): 추가 조치가 필요하여 클라이언트에게 다른 위치로의 리다이렉션을 요청한다.
- 4xx (클라이언트 오류): 클라이언트가 오류를 일으킨 상황. 잘못된 문법 등으로 서버가 요청을 수행할 수 없다.
- 5xx (서버 오류): 서버가 유효한 요청을 수행하지 못한 상황.
- 가장 흔히 볼 수 있는 상태 코드로는 200 (성공), 404 (찾을 수 없음), 500 (내부 서버 오류) 등이 있다.
## 웹 브라우저

- 웹 브라우저는 월드 와이드 웹을 탐색하기 위한 소프트웨어 응용 프로그램이다.
- 웹 서버로부터 웹 페이지나 이미지 등의 리소스를 요청하고, 받은 응답을 사용자에게 보여주는 역할을 한다.
- 주로 HTTP 또는 HTTPS 프로토콜을 통해 웹 서버와 통신하며, HTML, CSS, JavaScript와 같은 웹 기술을 해석하고 실행할 수 있다.
- 현대의 웹 브라우저는 멀티미디어 콘텐츠의 재생, 플러그인 또는 확장 프로그램의 지원, 북마크 관리, 개인정보 보호 등 다양한 기능을 제공한다.

## HTTP 서버 예시 코드
```java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleHttpServer {
public static void main(String[] args) throws IOException {
// 서버 소켓 생성
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("Server is listening on port 8080");
while (true) {
// 클라이언트 연결 수락
Socket clientSocket = serverSocket.accept();
System.out.println("New client connected");
// 요청 처리
try (BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
// 요청 라인과 헤더만 읽음
String line;
while (!(line = in.readLine()).isEmpty()) {
System.out.println(line);
}
// HTTP 응답 전송
out.println("HTTP/1.1 200 OK");
out.println("Content-Type: text/html");
out.println();
out.println("<html><body><h1>Hello, World!</h1></body></html>");
// 클라이언트 연결 종료
clientSocket.close();
} catch (IOException e) {
System.out.println("Connection error: " + e.getMessage());
clientSocket.close();
}
}
}
}
```
## HTTP 클라이언트 예시 코드
```java
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class SimpleHttpClient {
public static void main(String[] args) throws IOException, InterruptedException {
// HTTP 클라이언트 생성
HttpClient client = HttpClient.newHttpClient();
// HTTP 요청 생성
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:8080"))
.build();
// HTTP 요청 전송 및 응답 수신
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// 응답 출력
System.out.println("Response status code: " + response.statusCode());
System.out.println("Response body: " + response.body());
}
}
```