⚠️ 들어가기 앞서
경북대학교 컴퓨터학부 COMP0414-001 컴퓨터망 과목을 공부하며 정리한 글입니다.
네트워크 개념을 배울 때 빠질 수 없을 정도로 중요한 HTTP에 대해서 알아본다.
HTTP(HyperText Transport Protocol)은 응용 계층 프로토콜로서, 웹 페이지를 표시하는 데 사용된다.
웹 서버와 웹 브라우저 간의 데이터 전송을 위한 프로토콜이라고 이해하면 될 것 같다.
HTTP는 두 가지 특징이 있다.
따라서 웹 서버와 클라이언트 사이에 연결을 수립하고, 데이터를 주고받으며, 연결을 끊는다. 연결을 시작할 때와 종료할 때는 handshaking이 이루어진다.
handshaking에 대한 자세한 내용은 여기 참조!
stateless
하다'stateless' 말 그대로 상태가 없다
는 뜻이다.
서버가 클라이언트의 이전 상태를 보존하지 않는다
고 해석하면 된다.
예를 들어 다음과 같은 대화는 stateful
한 대화이다.
🤵 : 안녕하세요
👩 : 아메리카노 한 잔 얼마에요?
🤵 : 2,000원입니다.
👩 : 두 잔 주세요.
🤵 : 네, 결제는 뭘로 하시겠어요?
👩 : 카드로 할게요.
🤵 : 네, 결제가 완료되었습니다. 감사합니다.
위와 같은 대화는 종업원이 여자의 이전 질의를 기억하고 있기 때문에 "두 잔 주세요" 라고 했을 때 아메리카노를 뜻한다는 것을 알고 있다. 이렇게 대화 내용을 기억해야 한다면 매번 같은 서버가 연결되어 있어야 하고 오류가 발생했을 때 작업을 처음부터 다시 진행해야 한다는 단점이 있다.
그러나 만약 이 대화가 stateless하다면 다음과 같을 것이다.
🤵 : 안녕하세요
👩 : 아메리카노 한 잔 얼마에요?
🤵 : 2,000원입니다.
👩 : 두 잔 주세요.
🤵 : 네? 뭘 두 잔 달라는 말씀이신가요?
👩 : 아메리카노라고 방금 말했잖아요!
🤵 : 무슨 커피를 몇 잔, 결제는 어떻게 할 것인지 한 번에 말씀해주세요.
실제로 이런 대화가 오간다면 서로 복장이 터질 것이다. 종업원은 이전의 대화 내용을 전혀 기억하지 않고 있다. 즉 매번 다른 종업원이라고 봐도 될 것이다.
만약 프로토콜이 stateless하다면, 매번 들어오는 클라이언트의 요청에 어느 서버가 응답하더라도 상관이 없다. 따라서 서버 확장성이 높다. 또한 중간에 서버가 장애가 나더라도 다른 서버에 연결하면 되기 때문에 작업이 문제없이 이어질 수 있다.
그러나 클라이언트가 한 번에 많은 양의 데이터를 전달해야 한다는 단점도 있다. '아메리카노 2잔 체크카드로 결제할게요.' 와 같이 말이다.
HTTP 연결에는 두 가지 방식이 있다. 그 전에 RTT
라는 것을 먼저 알고 넘어가는 것이 좋을 것 같다.
RTT(Round-Trip Time) : 클라이언트가 서버로 패킷을 보낸 후 응답을 받을 때까지 걸리는 시간
위 그림을 보면 처음 클라이언트가 서버에게 연결을 수립하고자 inital TCP connection message를 보냈고, 거기에 따른 응답을 받았다. 메시지를 보낸 시점부터 응답을 받은 시점까지의 소요 시간이 바로 RTT이다.
여기서 중요한 점은 RTT는 transmission delay를 무시한다는 것이다.
즉 패킷을 '전송 완료' 한 시점부터 응답을 '받은 순간' 까지의 시간을 RTT로 정의한다.
TCP 연결 한 번에 하나의 객체를 전달할 수 있다. 여러 개의 객체를 전송하려면 여러 번의 TCP 연결이 필요하다.
오브젝트를 하나 보낼 때마다 연결을 열어야 하는데, 그 연결을 여는 과정이 1 RTT만큼의 시간이 소요된다. 그리고 오브젝트를 보내고 응답을 받는 시간에 1 RTT가 추가로 소요되고, 여기에 오브젝트를 보내는 시간인 file transmission time이 더해진다. 이 시간을 모두 더한 것이 HTTP response time
이다. RTT
와는 다른 개념이니 주의!
Non-persistent 체계에서 오브젝트 하나를 보낼 때의
response time
은2RTT + file transmission time
이 소요된다.
HTTP의 가장 초기 모델인 HTTP 1.0
은 non-persistent한 HTTP이다.
한번 열린 TCP 연결은 오브젝트를 주고받아도 닫히지 않고 열린 상태로 유지된다. 열려 있는 동안에는 여러 개의 오브젝트를 주고 받을 수 있다.
TCP 연결 한 번에 여러 개의 오브젝트를 주고 받을 수 있다.
최초 1회만 1 RTT 시간만큼을 들여 TCP 연결을 수립하면 되며, 그 뒤로는 오브젝트 하나당 1 RTT만이 소요된다. 즉 response time을 절반으로 줄일 수 있다.
HTTP 1.0
에서 개선된 버전인 HTTP 1.1
에서는 persistent한 HTTP 통신을 지원한다.
HTTP는 위와 같은 구조를 띠고 있다. 세 가지 부분으로 나눌 수 있다. request, line, header line, 그리고 body이다.
헤더의 각 줄에서 마지막에 위치한 cr
은 캐리지 리턴
이라는 뜻으로 각 줄의 시작 위치로 이동하라는 뜻이고 lf
는 라인 피드
, 새 줄을 의미한다.
즉 두 개를 같이 쓰면 한 줄을 내린다는 뜻으로 사용할 수 있으며 주로 CRLF
라고 묶어서 표현한다.
그리고 각 줄의 처음부터 CRLF가 나온다면 그 줄까지가 header lines이라는 뜻이다.
이 format을 실제 데이터로 채우면 다음과 같다.
header file의 맨 앞에 오는 'Method' 부분은 이 메시지가 어떤 요청을 뜻하는 메시지인지 알려주는 부분이므로 중요하다. 메소드의 종류는 다음과 같은 것들이 있다.
요청한 메시지에 대한 응답 또한 비슷한 구조를 띠고 있다. status line, header, body로 구성된다.
여기서 status line에는 status code와 text가 있는데, 요청에 대한 응답이 어떤지를 나타내는 부분이므로 중요하다. 코드의 종류에는 다음과 같은 것들이 있다.
200
: OK, 요청이 성공적으로 받아들여졌고 그에 대한 응답 또한 정상적으로 되돌려줄 수 있는 상태301
: Permanently Moved, 요청한 오브젝트가 영구히 이동했다는 뜻. 이동한 새 주소를 알려준다.400
: Bad request, 서버가 요청의 내용을 파악할 수 없는 상태404
: Not found, 요청한 정보가 서버에서 찾을 수 없는 상태505
: HTTP version not supported, 서버에서 지원되지 않는 HTTP 버전을 클라이언트가 요청하였다.304
: Not Modified, 클라이언트에게 응답이 수정되지 않았음을 알려주며, 그러므로 클라이언트는 계속해서 응답의 캐시된 버전을 사용할 수 있다. (후술)주로 사용하는 몇 가지 response들을 알아보았고 더 자세한 내용은 여기 참조
이전에 HTTP는 이전 상태 정보를 저장하지 않는 stateless
라고 하였다.
그러나 분명 이전 상태 정보를 저장해야 할 필요도 있을 것이다. 예를 들어 로그인 정보, 쇼핑몰에서의 장바구니 상태 등이다. 이렇듯 유저, 또는 서버의 상태를 부분적으로 유지할 수 있도록 하는 것이 쿠키
이다.
HTTP 쿠키(웹 쿠키, 브라우저 쿠키)는 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각이다. 브라우저는 그 데이터 조각들을 저장해 놓았다가, 동일한 서버에 재 요청 시 저장된 데이터를 함께 전송한다.
사용자가 특정 사이트에 처음으로 방문했을 때, 서버는 그 사용자를 식별하기 위한 고유 번호를 발급하여 서버의 데이터베이스에 저장해 놓는다.
그리고 어떤 사용자의 다음 HTTP 요청에는 쿠키 정보가 같이 포함되어 있다. 이 쿠키를 보고 자기들의 데이터베이스에서 찾음으로써 사용자를 식별할 수 있고, 기존에 저장된 정보를 활용할 수 있다.
proxy : [명사] 대리인
프록시 서버는 서버와 클라이언트 사이에서 대리로 서버의 역할을 하면서 통신을 수행한다.
프록시 서버의 존재 이유는 원래 서버를 거치지 않고 클라이언트의 요청을 수행하기 위함
이다.
클라이언트가 서버에게 특정 오브젝트를 요청하면, 서버는 클라이언트에게 응답을 돌려줌과 동시에 프록시 서버에도 오브젝트를 저장한다.
다음 번에 클라이언트가 다시 서버에게 동일 오브젝트를 요청하면, 프록시 서버에 존재하는 오브젝트이므로 서버를 거치지 않고 프록시 서버에서 바로 응답을 줄 수 있다.
캐시 메모리와 비슷하게 동작하므로 'web cache'
라고도 하며 동작 방식 또한 유사하다.
만약 프록시 서버에 존재하는 오브젝트여서 원래 서버를 거칠 필요가 없는 경우, 서버를 거치지 않고 응답을 받을 수 있으므로 response time
이 감소, 즉 성능이 향상된다. 또한 서버로 들어오는 요청 자체도 줄어드므로, 트래픽이 감소되는 효과도 있다.
클라이언트는 이전에 한 번 요청해서 돌려받은 오브젝트에 대해 다시 한 번 요청을 할 때, 이전과 같은 오브젝트를 받는다면 트래픽이 낭비될 것이다. 이에, 불필요한 트래픽을 줄이기 위해 해당 리소스가 변경된 경우에만 다시 보내달라고 요청할 수 있다.
즉, 클라이언트가 어떤 웹 페이지에 접근한 후, 다시 같은 페이지에 접근했을 때 서버가 다시 그 페이지의 내용을 전송하는 것은 낭비이다.
HTTP response는 마지막 수정 시간 정보를 가지고 있다.
클라이언트가 서버에게 "이 데이터가 이 시간 이후에 수정된 내용이 있는가?"
라고 물어보면 서버는 두 가지 응답을 할 수 있다.
200
OK, 수정한 내용을 알려 줌304
Not modified, 본 서버 말고 프록시 서버를 이용해도 문제가 없으므로 그 내용을 사용하라고 전달이 작업은 다음과 같은 시퀀스로 진행된다.
Last_Modified
필드가 포함된 객체를 응답메시지로 보낸다. Last-Modified
정보 즉, 객체의 마지막으로 수정된 날짜를 함께 저장한다는 것이다.~~~~
Last-Modified: Tue, 11 Apr 2023 01:23:45
~~~
~~~
If-modified-since: Tue, 11 Apr 2023 01:23:45
~~~
If-modified-since
값과 본 서버에 저장된 Last-Modifed
정보가 일치함을 확인할 수 있다. 만약 객체에 변경사항이 없다면 서버는 다음과 같은 메시지를 보낸다.HTTP/1.1 304 Not Modified
~~~
(body 비어 있음)
이는 클라이언트의 요청 객체를 프록시 서버에 복사된 복사본 객체 그대로 사용하라는 것을 의미한다. 따라서 프록시 서버는 저장된 객체를 클라이언트에게 전달한다.
만약 If-modified-since
값과 본 서버에 저장된 Last-Modifed
정보가 다르다면 서버는 200
응답과 함께 새로운 Last-modified
정보가 담긴 객체를 전해주며, 이를 프록시 서버에 저장하고 클라이언트에게 전달한다.
다음 글에서는 HTTP 1.0의 개선된 버전인 HTTP 1.1과 2.0을 이어서 살펴보고 SMTP, DNS에 대해서 알아본다.