HTTP는 현재 세계에서 가장 널리 쓰이는 프로토콜 중 하나이다. 우리가 보통 사용하는 인터넷을 위한 기본 프로토콜이기도 하며, 최근래에는 다루는 기술도 비약적으로 발전하여, 예전에 웹의 영역이 아니라고 불렸던 게임 영역, 실시간 대용량 처리, 대용량 메시지 처리 등에서도 HTTP 기반의 웹 스택을 사용하는 경우를 흔히 몰 수 있다.


HTTP TCP 계층의 위에 HTTP 프로토콜 스택을 쌓아올린 Network Layer로 현재 가장 널리 사용되고 있는 Stateless / Connectless 형식의 프로토콜이다.


 여기서 Stateless 란, TCP와 다르게 상호간의 연결된 소켓이 연결을 유지하지 않는다는 의미이다.

 즉, 서로 요청과 응답만 처리하고 "상태" 는 기록하지 않는다. 서로 간에 지속적인 "연결" 이 유지되지 않기때문에 지속적이면서 연속적인 통신에는 적합하지 않다. 일반적으로 채팅 서비스를 구현할때 HTTP가 고려되지 않는 이유이기도 하다.


 대신에 단순한 정보 전달에 있어서는 가장 효율적인 프로토콜이라고 봐도 무방하다. 요청한대로 응답만 보내주면 되기 때문에, 서버 입장에서도 연결 관리에 대한 부담이 덜어지고, 클라이언트 측면에서도 원하는 정보만 얻을 수 있으므로 효율적이다.


 HTTP 역시 네트워크 프로그래밍이기 때문에 당연히 소켓을 이용하여 통신을 하게 되며, HTTP를 서비스하는 웹서버는 특유의 성질을 구현하기 위하여 일반적인 TCP 서버 등과는 다른 HTTP 프로토콜에 특화된 형태를 취하게 된다.


소켓을 이용하여 RAW한 방식으로 HTTP 웹서버를 구축할 때는 연결이 시작된 이후에(Accept) 바로 해당 소켓의 연결이 요청(Request)을 받고, 응답(Response)한 후에 연결이 끊어지게 만드는 것을 잊지 않아야 한다.


 HTTP URI Method 등을 기반으로 작동하게 된다.

 HTTP 프로토콜은 별다른 것이 있는 것이 아니라 말그대로 Socket 의 통신 버퍼에 특유의 프로토콜 스택을 쌓아올리는 것을 말한다. 다음은 요청과 응답에 따른 프로토콜 형태이다.

 

<HTTP Request Header>


 위의 요청 포맷에서 첫번째 라인은 Request Line이라고 해서 요청에 대한 포맷 정보를 명시하는 필수 요소이다. 해당 라인은 3가지의 필드로 이루어져 있으며 각 필드는 다음을 명시한다.


(1)  요청 메서드 : GET, POST, OPTIONS(UPDATE, DELETE), PUSH 등의 요청 방식이 온다.


(2)  요청 URI : 요청하는 자원의 위치를 명시한다.


(3)  HTTP 프로토콜 버전 : 프로토콜의 버전으로 1.0 1.1이 있다.



그 아래로 요청 헤더의 내용이 CRLF Delimeter로 하여 열거된다.

General Header : Cache-Control, Connection, Date, Pragma, Trailer, Transfer-Enco, Upgrade, Via, Warning

Request Header : Accept, Accept-Charset, Accept-Encoding, Accept-Language, Authorization, Expect, From, Host, If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since, Max-Forwards, Proxy-Authorization, Range, Referer, TE, User-Agent

Entity Header : Allow, Content-Encoding, Content-Language, Content-Length, Content-Location, Content-MD5, Content-Range, Content-Type, Expires, Last-Modified, extension-header

요청 헤더의 내용이 전부 명시가 된 이후에는 Message Body두 개의 CRLF 아래에 명시된다. 두개의 CRLF 뒤에는 Request Body 가 포함되게 되며, 이부분은 HTTP 스펙에 따라서 해석의 여부가 나뉜다. (이부분은 REST API 소개 및 HTTP Method 분석 포스팅에서 자세히 다루겠다.)


 다음은 응답 헤더의 모습이다.


<HTTP Response Header>

 

첫번째 라인은 요청헤더의 Request Line 처럼 Response Header에서는 Status Line 이라 불리며 필수 정보를 포함한다.


(1)  응답 프로토콜과 버전 : HTTP/1.0, HTTP/1.1, HTTP/2.0 이 현재 버전으로 존재한다.


(2)  응답 코드 : 1xx, 2xx, 3xx, 4xx, 5xx 등의 번호가 응답 코드로 사용된다.


(3)  응답 메시지 : OK, Not Found, Internal Server Error 등의 메시지를 출력한다.


 역시 해당 라인 아래에 응답 헤더의 내용들이 포함되는데, Accept-Range, Age, Etag, Location, Proxy-Authenticate, Retry-After, Server, Vary, WWW-Authenticate 등의 정보가 포함된다. 이후에 두 개의 CRLF 라인 다음에 Message Body 가 첨부된다.

 


 복잡해보이지만 내부 구성원리는 간단하다. 

일반적인 TCP 서버를 구성하고, 프로토콜을 만드는데, 클라이언트로부터 요청을 받아서 해석하는 부분에 Request Parser를, 서버쪽에서 처리를 마치고 클라이언트에 응답을 내려줄 부분에 Response Builder 를 메시지의 머리에 붙여주면 된다.


 그렇게만 하면 웹서버가 HTTP Speculation 상에 약속한대로 메시지를 해석한다. 그렇다면 웹서버 작동의 기본 로직을 정리해보자.


(1) TCP 소켓을 열어 클라이언트의 접속을 받는다. (Accept)


(2) 커넥션을 관리할 수 있는 객체를 만들어, 쓰레드에 할당한다.


(3) 쓰레드가 해당 커넥션에 대해 HTTP Request 를 분석한다. Method 에 따라 서버 내에서 url Handler 를 라우팅해주고, 해당 라우터 메서드에서 요청에 대한 로직을 구현한다.


(4) 로직에 따라 구현한 HTTP Response 를 클라이언트에 반환하고, 접속을 끊는다. (Stateless)



좀 더 내부 동작 원리가 궁금하다면 자세한 예제는 다음 소스를 확인하면 도움이 될 것이다. 오래전에 작성한 소스라 허접하지만 웹서버 구현에 있어 기본에 충실한 좋은 예제라고 생각한다.

(https://github.com/ParkJinSang/Jinseng-Server)





TCP/IP 전송제어 프로토콜은 신뢰성에 초점을 맞추고 데이터가 신뢰성있게 올바른 순서로 유실되지 않게 빨리 전송할 수 있도록 설계된 프로토콜이다.


TCP 의 기본적인 작동 원리는 다음과 같다.

<TCP hand shake >

<출처 : https://wiki.mikrotik.com/wiki/Manual:Connection_oriented_communication_(TCP/IP)>


TCP 는 통신을 위해 3 way handshake 란 방식을 이용한다. 먼저 통신이 가능한지 SYN 을 보내고, 통신이 가능하다는 SYN-ACK을 받는다. 이 과정에서 문제가 없으면 이제 통신하고자 하는 메시지를 보내고, 양방향 통신이 된다. 이 과정을 3-WAY Handshake 라 하며, 이 과정은 TCP 매 통신 시마다 적용이 되며, 통신이 끝날때에는 SYN 대신 FIN 을 보내서 서로 확인을 받는다. 이러한 과정을 통해 TCP 는 무조건 메시지가 잘 전달되었으며 잘 도착했다는 확인을 받게 되고, 신뢰성을 보장받게 된다. 이러한 특성으로 TCP는 주로 전화에 비견된다. 이러한 TCP 통신을 위한 헤더는 다음과 같다.



위의 헤더 정보에는 보내는 메시지의 목적지 주소와, 순서 보장을 위한 일련 번호(Sequence Number), 에러 체크를 위한 Checksum 정보 등이 포함된다.

그 외에 사용하는 TCP 알고리즘 별로 슬라이딩 윈도우 정보 등 다양한 정보가 포함될 수 있다.


 슬라이딩 윈도우는 패킷의 흐름을 제어하기 위한 메모리 버퍼(Window) 로, 다양한 경우에 대비해서 사용된다. 가령 3WAY Handshaking 중 네트워크 장애 발생이나, 받은 메시지가 중간에 누락이 된 경우 해당 패킷의 재전송이 필요하다. 다음 패킷의 전송을 멈추고 이전 패킷의 전송을 기다리는 Stop And Wait 방식 보다, 훨씬 효율적일 수 있다.


<슬라이딩 윈도우 송신 측>


 위의 그림 처럼 슬라이딩 윈도우는 이미 전송하고 확인이 완성된 부분, 전송했지만 확인되지 않은 부분, 보내지 않았지만 수신자가 수신 준비 된부분, 수신준비 되지 않았으며 송신하지 않은 부분으로 영역을 나누어 네트워크 상황에 따라 포인터를 관리한다.


<슬라이딩 윈도우 수신 측>


 위의 그림은 수신측이다. 받았고 승인한 버퍼를 갖고 있으며 ( 이 버퍼는 나중에 다른 패킷으로 덮어써진다.) 수신자가 아직 받지 못한 부분, 수신준비되지 않았으며 수신하지 않은 부분으로 나뉘며 전송 상태에 따라 포인터를 조정한다.

(관련 내용의 예시를 잘 정리한 블로그는 다음을 참조하기 바란다. http://blog.naver.com/donjobani/30110435544)



 위의 내용들을 바탕으로 한 TCP 의 특징을 정리하자면 다음과 같다.


(1) Connection Oriented : 2개의 endpoint간 연결을 먼저 맺고 데이터 통신을 한다.


(2) Bidirectional byte stream : 양방향 Data stream(Byte stream)


(3) In-order delivery : 송신자가 보낸 순서대로 수신하며 Segment의 데이터 순서 표시를 위한 32비트의 정수를 사용한다.


(4) Reliability through ACK : 송신자는 수신자가 ACK 보내는 것을 체크하고 보내지 않은 데이터를 보관한다.


(5) Flow control : 송신측과 수신측의 처리 속도 차이를 해결하기 위해(특히 수신측이 느린 경우) 지원하는 제어 방식으로 흐름 제어라 불린다. 속도 차이로 전송 누수가 생기는 것을 방지하기 위해서 수신자는 받을 수 있는 버퍼의 크기(Receive window)를 송신자에 전달하여 송신자가 보내는 양을 제어하게 한다.


(6) Congestion control : 통신시 한 Router에 데이터가 몰려 혼잡할 경우, 호스트 들이 데이터 유실 때문에 재전송을 하게 되고 결국 혼잡이 더 늘어나는 악순환이 생긴다. 이를 막기 위해 송신측에서는 Congestion window가 존재하여 허용하는 만큼만 전송하게 하여 혼잡을 제어한다. TCP Vegas, BIC, CUBIC 등의 알고리즘을 사용한다.



 반면 UDP는 이러한 Hand shaking 과정이 없다. UDP 의 통신과정은 단순하다. 단순히 명시받은 IP 주소와 포트로 메시지를 UDP 헤더를 담은 메시지를 보낸다. UDP 헤더가 담긴 메시지를 받으면, 어플리케이션은 해당 메시지를 해독해서 로직을 처리한다. UDP 헤더는 다음과 같다. TCP 헤더보다 많이 단순한 모양이다.


 하지만 TCP 와 다르게 UDP 는 응답값을 기대하면 안된다. 신뢰성이 보장되지 않기 때문에, 중간에 네트워크 이슈로 인해 데이터가 손실되더라도 이를 알아차릴 방법이 없다. 그렇게 때문에 UDP 는 편지에 비유되며, 상대방 IP 주소의 포트에 메시지를 놓고온다고 이해하면 쉽다.


 정리하자면, TCP의 경우 좀 더 시간이 오래 걸리는 무거운 프로토콜이지만 신뢰성이 보장되며 UDP 의 경우 가볍지만 신뢰성을 보장할 수는 없다. 이런 특징 때문에 신뢰성이 중요한 메시지 들은 TCP로, 몇몇 패킷이 누락되어도 상관없는, 가령 이미지나 실시간 스트리밍 들은 UDP 로 구현이 된다.

 물론 몇몇 서비스의 경우에는 비즈니스 로직에 따라 UDP 로 구현하되, 헤더를 커스터마이즈하여 특정 조건에서 신뢰성을 갖으면서 가볍고 빠른 자체 프로토콜을 만들어 서비스 품질을 높이는 경우가 많다.






 DHCP란 Dynamic Host Configuration Protocol 의 약자로, 호스트의 동적 설정을 위한 프로토콜이다.


 장치들이 동적으로 적절한 IP주소들을 찾을 수 있도록 고안된 프로토콜로 2014년 기준 IPv4 네트워크의 표준이 되었다고 한다.


 TCP/IP 통신을 실행하기 위한 설정 정보의 할당을 관리하며 그를 위해 네트워크 관리자들이 IP 주소를 중앙에서 관리하고 할당할 수 있게 제공한다.


 OSI 상위 계층의 프로토콜들은 DHCP를 통해 결정지어진 IP 주소를 기반으로 인터넷을 이용하게 된다.



 인터넷에 접근 시 DHCP를 사용하지 않는 경우에는 컴퓨터마다 IP가 수작업으로 입력되어야 하며 다른 네트워크로 편입 시 IP 주소를 새로 받아야 한다. DHCP는 이를 자동으로 할당하게 끔 해준다.


(1)  DHCP Discover : 단말이 DHCP 서버를 찾기 위해 동일 Subnet 상에 브로드캐스트.


(2)  DHCP Offer : DHCP 서버가 단말로 단말에 할당할 IP, Gateway IP 등 네트워크 정보를 송신


(3)  DHCP Request : 단말이 DHCP 들 중 자신이 사용할 DHCP 서버를 선택하고 해당 서버에 자신이 사용할 네트워크 정보를 요청


(4)  DHCP ACK : 선택된 DHCP 서버가 단말로 네트워크 정보를 송신 -> 인터넷 가능

 

 

본 내용은 위키에도 잘 정리되어있으니, 좀 더 공부하고자 한다면 참고하면 좋다.

(https://ko.wikipedia.org/wiki/%EB%8F%99%EC%A0%81_%ED%98%B8%EC%8A%A4%ED%8A%B8_%EA%B5%AC%EC%84%B1_%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C)



+ Recent posts