놓치고 넘어간 것.04 TCP/IP 모델과, HTTP 프로토콜

Sal Jeong·2022년 8월 13일
0

이전에 간단히 정리한 OSI 모델 이후 나타난 모델과, 그 중 Application Layer의 http 프로토콜에 대해서 정리해보고자 한다.

1. TCP/IP Model

TCP/IP(Transmission Control Protocol/Internet Protocol) 모델이란 간단하게 말하면 OSI 모델의 간략화된 버전이다. 7계층이 아닌 4계층으로 이루어져 있다.

ex)여기서 또다시 개선되어 위 Internet Layer가 Network(or Internet) Layer, Data Link Layer로 나뉘어지게 되엇다. 현재 전세계 표준은 위 5단계 TCP/IP 모델이다. 사실 OSI 계층이 먼저 인 줄 알았지만, 의외로 TCP/IP가 1974년, OSI 모델은 1984년 나온 것이라고 한다.

두 모델의 차이점:

  1. OSI 모델은 네트워크 전체의 작동을 설명하는 일종의 관념에 가깝다면, TCP/IP 모델은 인터넷에 연결된 디바이스 상의 통신을 좀 더 명쾌하게 설명함

  2. OSI 모델은 계층 간의 수직 연결성을 설명하지만 TCP/IP 모델은 계층이 평행하게 연결되어 있다.

  3. TCP/IP 모델은 어플리케이션 레이어 하나만 존재하지만, OSI에서는 Session, Presentation과 Application이 존재한다.

  4. Physical Layer

OSI의 1. 피지컬 레이어와 동일하다. bit 데이터를 보내고 받으며 네트워크 장비의 유니크한 MAC 주소를 가지고 있다.

  1. Data Link Layer(MAC)

1.에서 받은 bits를 frame으로 생성한다. 해당 프레임은 윗 단계 네트워크 프레임에서 MAC 주소와 도착지 정보를 가진 패킷이 된다.

  1. Network Layer(IP)

네트워크 레이어는 2.에서 받은 프레임을 패킷으로 만든다. 패킷에는 패킷의 출발지와 도착지가 IP주소의 형태로 담긴다.

  1. Transport Layer

트랜스포트 레이어는 어플리케이션 계층과의 연결을 TCP/IP과 UDP 프로토콜을 사용해 실시한다.
TCP/IP는 유실되어서는 안되는 정보에, 속도가 중요하다면 UDP를 사용한다. 해당 프로세스를 위해 포트 너머를 할당한다.

  1. Application Layer

어플리케이션 레이어는 앱이 활동하는 계층이다.(서버 앱, 프론트 앱) 메시지 신택스를 사용하여 데이터를 주고받으며, 이번 메인 주제인 http 프로토콜이 여기 속한다.
HTTP - 사실은 이 이야기를 하고 싶었는데, 역시 간단하게 정리할 내용이 아니다보니..
FTP - TCP/IP 환경에서 데이터를 교환하기 위한 프로토콜
SNMP - 동일한 네트워크에 접속된 기기들을 제어하고 확인하기 위한 프로토콜
DNS - 사람이 읽을 수 있는 도메인을 IP 주소로 교환한다.

2. 그렇다면, http 프로토콜은 무엇일까?

Hypertext Transfer Protocol(HTTP)란, HTML문서와 같은 리소스를 요청하고 전달받는 규범이다. 웹 상에서 클라이언트-서버 구조를 가진 서비스 간에서 일어나는 데이터 전달 흐름을 말하며, 웹 브라우저가 실행 주체가 된다. HTML 문서를 받아온 후에, 그 외 파일들(텍스트, CSS, 이미지, 비디오, JS 등)을 추가적으로 요청하는 구조가 된다.

상술햇듯 메시지 신택스를 사용해 클라이언트와 서버간의 연결이 일어나게 되는데(데이터 스트림과의 반대 개념), 주체인 브라우저에서 서버로 보내는 요청은 requests, 서버에서 보내는 메시지는 response라고 부른다.

http 프로토콜은 1990년대에 디자인 되었고 지금까지 계속해서 개량되어 사용하는 프로토콜이다. 어플리케이션 레이어에서 TCP 프로토콜이나 / TLS로 암호화된 TCP 연결을 통해 아래 Transport Layer와 통신하고, 이론적으로는 어떠한 다른 프로토콜을 사용해도 문제가 없다. 하지만 HTTP의 범용성으로 인해, HTML만을 수신받는 것이 아니라 이미지, 비디오를 요청하거나 서버에 컨텐츠를 POST로 송신하거나와 같이 다양한 용도로 사용된다. 또한 On-Demand 방식으로 문서의 일부분만을 최신화 할 수 있다.

3. HTTP 프로토콜의 컴포넌트 종류

HTTP는 클라이언트-서버 구조 기반이다. 리퀘스트는 한 브라우저(하나의 클라이언트)에서 이뤄지고, 이때 송신자는 user agent가 된다.(프록시를 통하는 경우는 프록시), 대부분 유저 에이전트는 웹 브라우저이지만, 검색 엔진을 위해 크롤링하는 봇이 될수도 있다.
각각의 리퀘스트는 서버에 보내져서 각각의 리스폰스를 수신받게 된다. 클라이언트와 서버 간 프록시라는 개체가 존재할 수 있으며, 게이트웨이, 캐시와 같은 역할을 한다.

실제 상황에서는 브라우저와 서버 사이에 더 많은 단말이 존재할 수 있다. 라우터, 모뎀 등등... 위 모델 개념으로 인해서, 이것들은 실제 사용자에겐 노출이 되지 않고 Network 과 Transport layers에 위치한다. HTTP는 apllication layer에서 동작한다.

  1. client: user-agent
    유저 에이전트란 유저를 대신하는 어떠한 툴이다. 대부분 브라우저가 되거나, 혹은 어떤 프로그램, 앱이 될 수 있다. 브라우저는 항상 리퀘스트 자체를 시작하는 주체가 된다. 원칙적으로, 서버는 결코 메시지를 시작하지 않지만 서버에서 보내지는 요청도 추가되고 있다.
    웹 페이지를 렌더링하기 위해서, 브라우저는 HTTP 프로토콜을 기반으로 한 리퀘스트를 해당 도메인에 보내게 된다. 받은 프일을 파싱하여 추가로 필요한 리소스들을 요청한다. (CSS, JS, 스태틱 파일들) 이러한 파일들을 조합해 완성된 문서가 바로 웹 페이지가 된다.
    웹 페이지는 하이퍼텍스트 문서를 일컫는다. 이 하이퍼텍스트에는 링크라는 요소가 추가 되는데, 클릭을 함으로써 다시 위의 프로세스가 일어나게 되고 이것이 바로 웹을 navigate한다는 뜻이다.

  2. Web Server
    클라이언트의 반대편에는 웹 서버가 있다. 위 클라이언트가 요청한 문서를 serve 하는 역할을 담당한다. 서버는 하나의 단말이 될 수도 여러 서버의 집합체가 될수도 있다. 이 경우 load balancing이나 다른 소프트웨어적 방법을 통해서(cache, CB server, e-commerce servers)단독이나 혹은 여럿이서 문서를 제작하여 response로 내려주게 된다.

또한, 하나의 단말에서 여러 개의 서버를 띄울 수 있다. 이 경우 HTTP/1.1 환경에서 한 서버가 같은 IP 주소를 공유하게 된다.

프록시
상술했던 대로 브라우저와 서버 사이에는 많은 계층에서 다른 컴퓨터들이 존재한다. 위 TCP/IP 모델링에 따라, 이 프록시들은 트랜스포트, 네트워크 혹은 피지컬 레벨에서 HTTP 어플리케이션 레이어와는 다르게 동작하고, 이 부분을 간과하면 퍼포먼스에 큰 문제가 생길 수 있다. 프록시는 이 컴퓨터들 중 어플리케이션 레이어에서 동작하는 컴퓨터이다.
이들은 클라이언트의 리퀘스트를 변화하지 않고 포워딩 하거나, 아니면 리퀘스트 자체를 변화시켜 목적지 서버에 도달시키는 목적을 가지고 있다. 프록시의 목적들은 다음과 같다.

캐싱(브라우저 캐쉬처럼, 퍼블릭과 프라이빗 캐쉬로 나뉜다.)
필터링(안티바이러스와 같은 것들이 해당한다)
로드 밸런싱(여러 리퀘스트를 컴퓨터를 나누어 처리하기 위함)
인증(다양한 리소스에 접근 권한을 주기 위해서)
로깅(해당 스토리지의 기록을 위해)

4. HTTP의 기본 성질

  1. HTTP는 간단해야 한다.
    간단하고 인간이 읽을 수 있게 디자인 되어야 한다. HTTP 메시지 역시 인간이 읽을 수 있어야 테스팅/ 디버깅을 할 수 있기 때문이다.
    HTTP 2.0 사양의 경우 HTTP 메시지가 프레임화 되기 때문에 더 복잡해지지만, 그래도 1.의 원칙을 지켜야만 한다.

  2. HTTP는 범용적이여야 한다.
    HTTP/1.0부터 HTTP 헤더를 사용해 프로토콜의 확장을 쉽게 만들 수 있었다. 이러한 헤더의

  3. HTTP는 stateless 하지만 sessionless는 아니다.
    HTTP는 스테이트리스이다. 각각의 requests는 독립되어 있기 때문에, 몇몇 특수한 경우(e-commerce의 장바구니 같은 경우) 구현하는 것이 어려울 수 잇다. 그래서 cookie를 브라우저에 심어둠으로써 session의 역할을 할 수 있다. header 자체는 수정 가능한 오브젝트이기 떄문에, cookie가 리퀘스트의 중간에서 header를 수정해 줌으로써 http 리퀘스트들이 같은 컨텍스트나 스테이트를 가지게 할 수 있다.
    // 그렇다면 쿠키와 세션, 토큰의 차이는?

  4. HTTP 연결
    네트워크 연결은 transport layer에서 일어나는데, HTTP의 스코프에서는 벗어나 있다. 하지만 HTTP는 연결을 기반으로 한 전송 프로토콜을 보유하고 있지 않고 데이터 손실이 없고 믿을 만한 연결방식을 요청할 뿐이다. TCP는 그렇고 UDP는 안정성이 보장되어 있지 않다. 그렇기 때문에 HTTP는 TCP를 연결방식으로 사용한다.
    상술했듯 클라이언트와 서버의 리퀘스트/ 리스폰스 교환이 일어나기 위해선, TCP 연결을 통해 먼저 주소를 알아내어야 한다. 그리고 HTTP/1.0 사양에서는 하나의 request/response 마다 하나의 TCP 연결을 사용하는데, 이 부분이 효율성을 크게 해치게 된다.
    (핸드쉐이크 과정이 계속 반복되기 때문이다! 서로 연결할 때는 3 way handshake, 연결을 끊을 때는 4 way handshake가 된다.)

이 문제를 해결하기 위해서, HTTP/1.1에서는 파이프라이닝(구현하기 어렵다고 알려져 있지만)과 persistent connection의 개념을 도입했다. Connection header를 사용해 TCP 연결을 제어할 수 있는 것이다.
p.s1:Header에 connection: keep alive라고 되어 있는 항목이 이것, 하지만 서버는 연결 세션을 유지해야 하므로 이 부분에서 성능저하가 발생했다.
p.s2:파이프라이닝으로 인해 HOL 문제가 발생한다.
요청 하나하나씩을 순차적으로 처리하는 구조 상, 10초, 1초가 걸리는 요청을 순차적으로 보내면 1초가 먼저 끝났음에도 10초의 요청이 끝나야만 2를 처리할 수 있다.

HTTP/2에서는 여기서 더욱 발전해 multiplex를 도입했다. 하나의 TCP 연결로 계속해서 메시지 전달을 할 수 있게 되었다.
p.s1)
1. binary framing
텍스트 형식인 메시지를 binary 형태로 보내게 되어, 컴퓨터의 파싱 시간이 줄어들었다.
2. multiplex streaming
HTTP/1.1의 파이프라인 개념과는 다르게, 양방향 데이터 흐름이 가능하다.
p.s.2) 정확한 것은 더 찾아봐야 알겠지만, 위의 전통적인 TCP handshake 없이 계속해서 메시지를 보낼 수 있다.

구글에서는 새로운 UDP 기반 QUIC을 실험하고 있다.
(생각하길, html/2.0의 멀티플렉싱 구조가 핸드쉐이크를 생략해 시간적 이득을 준다면, UDP와 크게 다른게 없는 거 아닐까?)

5. HTTP는 무엇을 할 수 있는가?

캐싱 - 서버는 클라이언트와 프록시에게 해당 리소스가 얼마나 캐싱될 것인지 지정해 줄 수 있다. 이 경우 클라이언트에서 캐싱된 리소스 요청을 무시하라고 프록시에 요청한다.

CORS 완화 - 악용을 방지하기 위해서, 웹 브라우저는 오직 동일한 오리진만이 한 웹 페이지의 전체 데이터를 가져오도록 한다. HTTP 헤더를 수정해 주어 이 제약을 완화할 수 있다.
P.S.1) React로 작업하면서 로컬 서버, 혹은 작업 서버에서 요청을 보낼 때 CORS 이슈를 항상 볼텐데, 그 이유는 localhost:3000(기본)으로 지정된 리액트의 로컬 서버에서 localhost:8000과 같은 다른 오리진으로 요청을 보내기 때문입니다. 프록시 지정으로 해결가능

인증 - 어떠한 인증 정보를 가진 유저에게만 보여주는 페이지를 만들 수 있다. 기본 인증은 WWW-Authenticate 헤더를 통하거나 cookie를 통한 세션으로 가능하다.

인트라넷에 속한 프록시와 터널링 서버, 클라이언트는 자신의 진짜 IP 주소를 숨길 수 있다. 이러한 개체에서 보내는 HTTP requst는 프록시를 통해 자신의 네트워크 바깥으로 나가는데, 모든 프록시가 HTTP proxy인 것은 아니다. 예를 들면 SOCKS같이 더 아래 계층에서 활동하는 것도 있다.
ftp는 이 HTTP proxy로 동작한다.

쿠키를 이용한 세션은 리퀘스트를 'state'와 함께 보낼 수 있게 해준다. 이것으로 세션이 만들어지고, HTTP의 스테이트리스 로직과 맞지는 않는다. 이 부분의 대표적인 사례로는 e-commerce 장바구니가 있다.(여러 요청이 계속해서 이어질 수 있으므로)

6. HTTP의 flow

클라이언트가 서버나 프록시와 통신할때, 아래의 단계가 있다.

  1. TCP 연결을 시도한다.
    TCP 연결을 통해 한 번 혹은 여러번의 request를 보낸다. 클라이언트는 새로운 연결을 시작하거나, 현재 있던 연결을 재사용하거나, 혹은 여러개의 연결을 새로 열 수 있다.
  2. HTTP 메시지를 보낸다.
    HTTP/2 이전의 HTTP 메시지는 인간이 읽을 수 있는 형태이다. 하지만 HTTP/2의 메시지는 프레임으로 캡슐화된 상태이므로 그대로는 읽을 수 없지만, HTTP의 원칙 자체는 그대로다.
GET / HTTP/1.1
Host: developer.mozilla.org
Accept-Language: fr

이러한 요청이 있다면,


HTTP/1.1 200 OK
Date: Sat, 09 Oct 2010 14:28:02 GMT
Server: Apache
Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT
ETag: "51142bc1-7449-479b075b2891b"
Accept-Ranges: bytes
Content-Length: 29769
Content-Type: text/html

<!DOCTYPE html>… (here come the 29769 bytes of the requested web page)

이런식의 사람이 읽을 수 있는 형태의 메시지를 받는다.

  1. 연결을 끝내거나, 연결을 재사용한다.

만약 HTTp/1.1 사양의 파이프라이닝이 켜져 있다면, 첫번째 요청이 다 끝나기 전에 다른 요청들을 보낼 수 있다. 하지만 여러 이유로 인해 HTTP/2에서는 더 안정적인 멀티플렉싱으로 프레임 스트림을 보내는 방식으로 대체되었다.

7. HTTP의 message

HTTP 메시지는 기본적으로 인간이 읽을 수 있는 형태지만 HTTP/2에서는 메시지가 프레임 바이너리 구조로 감싸져 있기 떄문에 그대로는 읽을 수 없다. 하지만 이 부분이 최적화 상 큰 도움이 된다.

HTTP/2의 메시지 구조가 1.1과 다르다고 하더라도, 시멘틱스 자체는 변했지 않았고 클라이언트에서 1.1의 구조로 다시 바꾸어 주기 때문에, 이 부분을 이해하는 데는 문제가 없다.

  1. Request

요청은 다음 요소로 구성된다.

HEEP 메소드. GET, POST, OPTIONS HEAD 등으로 클라이언트가 원하는 액션의 종류이다. 일반적으로, 클라이언트는 GET으로 어떠한 리소스를 요청하고, HTML form 으로 값을 POST한다. 이외에도 다양한 케이스가 있다.

리소스의 경로. URL에서 resource 경로를 확인할 경우, 다른 부분들을 지워나가면 된다.
HTTP://developer.mozilla.org 에서 메소드 제거
developer.mozilla.org 에서 도메인 제거
TCP port 제거(여기 나오지는 않지만 80)
하면 /가 남으므로 결국 메인 페이지를 호출하는 것이 된다.

HTTP 프로토콜 버전

그리고 이외 정보들을 담고 있는 헤더. 이 요청의 경우 "Accept-Language": "FR"
또한 POST의 경우 body에 어떠한 리소스를 넣어서 보낸다.

p.s.1)
GET의 경우는 domain.com?qs=qs 처럼 쿼리스트링으로,
POST는 body: {}의 형태로 보낸다.

응답의 경우,

HTTP 버전, 스테이터스 코드와 메시지.
HTTP Headers
또한 요청한 resource를 담은 body로 구성된다.

8. HTTP API

가장 일반적인 HTTP API는 XMLHttpRequest API이다. user agent와 서버간 통신에 사용되고 새로운 Fetch API는 더 강력하고 유연한 기능을 제공한다.

이외에 server-send events는 서버가 클라이언트에 단방향으로 메시지를 보낼 때 사용된다. 이 경우 HTTP는 전송 메커니즘으로 작동하며, EventSource 인터페이스로 연결을 시작하고 이벤트 핸들러를 설정한다. 클라이언트의 브라우저가 자동으로 서버 메시지를 HTTP 스트림으로 받아서, 적절한 이벤트 오브젝트로 반환한다. 해당 이벤트 핸들러의 타입이 코드가 알고 있다면(Known) 해당 핸들러로 반환하고, 아니라면 onMessage 핸들러로 반환한다.

9. 결론

HTTP 는 광범위하고 쉬운 프로토콜이다. 헤더를 설정할 수 있고 클라이언트 서버 구조에서 동작하기 때문에 웹과 함께 발전해 왔다.

HTTP/2가 메시지 해독을 어렵게 만들기는 하지만, 이는 최적화 측면에서 도움이 되고 실제 메시지는 HTTP/1.0 양식에서 변화하지 않았다. 세션 플로우도 마찬가지로 간단하고 message monitor와 같은 툴로 확인하고 디버깅할 수 있다.

https://firefox-source-docs.mozilla.org/devtools-user/network_monitor/index.html

다 정리해놓고 보니, 결국 MDN 문서를 한글로 번역한 것에 지나지 않았다.
역시 MDN은 위대하다...

참고한 문서

https://www.geeksforgeeks.org/tcp-ip-model/

https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview

https://microchipdeveloper.com/tcpip:tcp-ip-five-layer-model

https://www.baeldung.com/cs/http-versions
profile
행복하기 위해 코딩합니다. JS 합니다.

0개의 댓글