[네트워크] 웹과 HTTP

참고도서: 컴퓨터 네트워킹 : 하향식 접근. 7판. James F. Kurose , Keith W.Ross 지음

HTTP(HyperText Transfer Protocol)

  • HTTP는 웹의 어플리케이션 계층 프로토콜이다.
  • HTTP는 클라이언트와 서버프로그램으로 구현되고 두 프로그램이 HTTP를 통해 메세지를 주고받으며 통신한다.
  • 웹 페이지는 객체(object) 로 구성되어 있고 일반적으로 기본 HTML 파일과 다른 참조객체들로 구성되어있다. 기본 HTML은 페이지 내부의 다른 객체들을 URL(Uniform Resource Locator)을 통해 참조하게 된다.
  • HTTP는 TCP를 전송 프로토콜로 사용한다. 클라이언트는 서버와 소켓 인터페이스를 통해 TCP연결을 수행하고 메세지를 주고받게 된다.
  • HTTP는 비상태 프로토콜(Stateless Protocol)이다. 서버는 클라이언트에 대한 어떤 상채 정보도 저장하지 않는다.

비지속 연결과 지속 연결

비지속 연결(non-persistent connection) HTTP

  • 비지속 연결은 한번의 request/response 가 끝나면 연결이 끊어지게 되는 것을 의미한다.
  • HTTP 클라이언트가 어떤 웹사이트에 접속을 시도한다고 생각해보자

    • HTTP 클라이언트와 서버는 서로 소켓을 통해 TCP 연결을 설정한다.
    • 클라이언트는 TCP 연결소켓을 통해 서버로 request 를 보낸다.
    • 서버는 requesst 메세지를 받아 저장장치에 있는 객체를 추출하고 캡슐화해서 소켓을 통해 클라이언트에게 응답메세지를 보낸다.
    • 클라리언트가 응답을 받으면 TCP 연결을 끊는다.
    • 만약 방금 가져온 객체에 참조객체들이 있다면, 위 단계들을 반복하면서 모든 객체들을 서버로부터 받아온다.
  • 일반적으로는 한번에 하나의 연결만을 설정하면 시간이 오래 걸리기 때문에 한번에 다수의 TCP 연결을 만들어서 서버로부터 객체를 가져온다.
  • 통신을 위한 작은 패킷이 클라이언트로부터 서버로 이동했다가 다시 클라이언트로 돌아오는 시간을 RTT(Round Trip Time)이라고 한다.
  • TCP 연결을 위해서 클라이언트와 서버가 TCP 메세지를 주고받는 과정을 세 방향 핸드셰이크(3-way handshaking) 이라고 하는데, 이 핸드셰이크는 다음과 같은 과정으로 일어난다.

    • 클라이언트가 서버로 TCP 메세지를 보낸다.
    • 서버가 메세지를 받았다는 의미로 ACK 패킷을 보낸다.
    • 클라이언트가 서버로 TCP 메세지와 요청메세지를 함께 보낸다.
  • 위 핸드셰이크 과정에서 첫 두단계를 거치면 1 RTT 가 소요된다. 그리고 3번째 단계에서는 클라이언트가 보낸 요청 메세지와 TCP 메세지에 대한 응답을 받아야하기 때문에 1 RTT 와 요청한 파일을 받는시간 이 소요된다.
  • 따라서 비지속 연결 HTTP에서는 하나의 파일을 요청하고 받는데 총 2 RTT + 파일전송시간 이 소요되게 된다.

지속 연결(persistent connection) HTTP

  • 지속 연결은 한 번의 연결 이후에 계속해서 메세지를 주고받을 수 있게 하는 방법이다.
  • 서버가 한 요청에 대한 응답 메세지를 보낸 이후에 연결을 끊지 않고 유지하게 된다.
  • HTTP 1.1 에서는 기본적으로 설정되어 있는 방법이다.
  • 지속 연결을 사용하면 항상 2 RTT 를 사용해야하는 비지속 연결보다 효율적으로 객체들을 응답받을 수 있다는 장점이 있다. 첫 연결이 설정된 이후에는 요청과 응답만 있으면 되기 때문에 1 RTT + 파일전송시간 만 있어도 파일을 전달받을 수 있다.
  • 여기에 파이프라인 기법을 추가적으로 사용하기도 하는데, 클라리언트가 요청에 대한 응답을 서버로부터 받기 전에 새로운 요청을 만들어서 서버로 보내는 방법이다. 이렇게 하면 모든 참조객체에 대해 1 RTT 보다 작은 오버헤드가 사용될 것이다.

HTTP 메세지 포맷

HTTP 요청 메세지

  • HTTP의 요청 메세지는 ASCII 텍스트로 작성되어 있어 읽기 쉽게 만들어져있다.
  • 요청 메세지는 요청라인, 헤더라인, 개체몸체 로 구성된다.
  • 요청 메세지의 첫 라인을 요청 라인이라고 하고 요청 방식, 객체의 URL, HTTP 버전 이 작성되어져 있다.
  • 이후 라인들은 공백라인이 나타날 때까지 헤더라인으로 구분한다. 헤더라인은 host, connection, user-agent, accept-language 등 다양한 헤더 정보들이 포함된다.
  • 헤더 라인 뒤 공백라인의 다음에는 개체 몸체(Entity Body) 가 나온다. 개체 몸체는 POST 방식에서만 사용되고 사용자가 폼 필드에 입력한 값들이 이곳에 들어간다.

HTTP 응답 메세지

  • 응답 메세지 역시 ASCII 텍스트로 작성되어 있다.
  • 응답 메세지는 상태라인, 헤더라인, 개체몸체 구성된다.
  • 상태라인에는 HTTP 버전, 상태 코드, 상태 메세지 가 작성되어져 있다.

    • 상태 코드는 다음과 같이 구분한다.
    • 200번대: 성공
    • 300번대: 객체 이동
    • 400번대: 오류
  • 헤더라인에는 connection, date, server, last-modified, content-length, content-type 등 다양한 헤더 정보들이 포함된다.

쿠키(Cookie)

  • HTTP는 상태정보를 저장하지 않는 stateless protocol 이다. 하지만 우리는 종종 어떤 웹사이트에 접속했을 때, 내가 이전에 입력했던 정보들이 자동으로 저장되어있는 것을 확인할 수 있다. 이 모든 것은 쿠키라고 불리는 기술이 있기 때문에 가능하다.
  • 쿠키는 네 요소들을 기존 기술에 추가함으로 구현할 수 있다.

    • HTTP 응답 메세지에 Set-cookie 헤더를 포함시킨다.
    • HTTP 요청 메세지에 Cookie 헤더를 포함시킨다.
    • 사용자 브라우저가 관리하는 쿠키파일을 생성한다.
    • 웹사이트의 백엔드에 사용자에 대한 데이터베이스를 가진다.
  • 쿠기의 생성과 관리는 다음과 같은 순서로 진행된다.

    • 사용자가 어떤 웹사이트에 접속했을 때, 서버는 접속요청을 받으면서 해당 사용자에 대한 고유한 식별번호를 만든다.
    • 해당 식별번호가 서버의 백엔드 데이터베이스에 있는지 확인한다.
    • 데이터베이스에 해당 식별번호를 인덱스로 가지는 정보가 없다면, 서버는 응답메세지에 Set-cookie 헤더를 포함시켜서 사용자에게 보낸다.
    • 응답을 받은 사용자의 브라우저는 Set-cookie 메세지를 확인하고 브라우저가 가진 쿠키파일에 Set-cookie 헤더에 담긴 사용자 식별번호를 기록한다.
    • 다시 사용자가 같은 웹사이트에 접속을 요청했을 때, 요청메세지에 쿠키파일에 들어있던 식별번호를 확인해서 Cookie 헤더에 포함시킨다.
    • 서버가 요청메세지를 받았을 때, Cookie 헤더에 포함된 식별번호를 인덱스로 가지는 데이터베이스 정보가 있기 때문에 데이터베이스 안에있는 모든 정보들을 해당 사용자와 연결시켜서 사용하게 된다.

웹 캐싱/프록시 서버(Web Caches/Proxy Server)

  • 웹 캐시는 클라이언트와 서버 사이에서 자체적으로 저장디스크를 가지고 최근에 호출된 객체의 사본을 저장하는 네트워크 개체이다.
  • 웹 캐시는 다음과 같은 과정으로 동작한다.

    • 클라이언트는 일단 웹 캐시와 TCP 연결을 설정하고 HTTP 요청메세지를 보낸다.
    • 웹 캐시는 요청받은 객체의 사본이 자신에게 저장되어 있는지 확인하고 저장되어 있다면 해당 객체를 HTTP 응답메세지와 함께 클라이언트로 보낸다.
    • 만약 객체의 사본이 웹 캐시에 없다면, 웹 캐시는 본 서버와 TCP 연결을 설정하고 HTTP 요청메세지를 보낸다.
    • 본 서버는 응답메세지와 함께 자신의 객체를 웹 캐시로 보낸다.
    • 객체를 받은 웹 캐시는 해당 객체의 사본을 저장하고 클라이언트로 응답메세지와 함께 객체를 전송한다.
  • 웹 캐시를 사용하면 클라이언트의 요청메세지에 빠르게 응답할 수 있고, 서버로 몰리는 트래픽을 분산시켜서 트래픽 강도를 크게 낮출 수 있다.
  • 하지만 웹 캐시가 가지고 있는 정보가 항상 최신의 정보라는 보장이 없다. 이 문제를 해결하기 위해서 조건부 GET(Conditional GET) 을 사용한다.

    • 조건부 GET을 현재 시스템이 사용하는지 확인해보려면, HTTP 메세지가 GET 방식을 사용하고, 동시에 If-Modified-Since 라는 헤더를 포함하고 있는지 확인해보면 된다.
    • 캐시에 저장된 객체들은 마지막으로 수정된 날짜에 대한 정보를 가지고 있다.
    • 웹캐시는 자신이 가지고 있는 객체의 수정된 날짜를 If-Modified-Since 헤더에 포함시켜서 서버로 요청메세지를 보낸다.
    • 서버는 자신이 가지고 있는 객체의 수정날짜와 요청메세지의 날짜를 비교해서 두 날짜가 일치하는지 웹 캐시에게 응답메세지의 코드를 통해 알려준다.
    • 상태코드를 읽고 수정된 기록이 없다면 웹 캐시는 자신이 가지고 있는 객체를 클라이언트에게 보내주고, 수정된 적이 있다면 다시 본 서버로 요청메세지를 보내서 캐시를 받아오고 업데이트한다.

HTTP/2

  • HTTP/2 버전은 Stream 개념을 처음으로 도입한 버전이다.
  • 기존 HTTP/1.1 이 한번에 여러 데이터를 전송할 수 없었던 이유는 여러 요청이 한번에 들어올 경우에 응답을 어떻게 요청과 짝지을 것인지에 대한 문제때문이었다. 따라서 각 요청마다 TCP 연결을 각각 설정해서 동시에 여러 TCP 연결을 만드는 방식을 사용했다.
  • 하지만 HTTP2 에서 Stream 개념이 도입되면서 각 스트림에 고유번호를 지정해서 한번에 여러 요청들을 서버로 보내고, 서버는 해당 고유번호를 사용해서 demultiplexing 하는 방식으로 요청을 구분하고 응답을 보낸다.
  • 또한 stream에 가중치를 추가해서 현재 네트워크가 가진 총 리소스를 가중치에 따라 부여할 수 있는 기능도 추가되었다.
  • Server Push 라는 기능도 추가되었는데, 클라이언트가 직접적으로 요청하지 않은 리소스가 기본 HTML에 포함되어 있다면, 서버 측에서 먼저 클라이언트 쪽으로 리소스를 보내주는 방식이다. 이 방식을 사용하면 클라이언트가 따로 요청을 보내지 않아도 필요한 리소스들이 서버로 부터 전송되기 때문에 request-response 시간이 단축된다.

Written by@전여훈 (Click Me!)
고민이 담긴 코드를 만들자, 고민하기 위해 공부하자.