IP와 TCP
서문
원래는 자바의 정석의 네트워크 파트에 대한 포스팅을 작성하려고 했으나, 생각했던 것과 달리 JAVA에서의 네트워크 연결과 사용 방식에 대해 나와있을 뿐이고 내가 원하던 네트워크에 대한 CS는 없었다.
네트워크에 대해 알지 못하는데 네트워크의 사용방식에 대해 포스팅하는 것이 어불성설이라 여겨져 먼저 네트워크에 대한 공부를 선행하기로 했다.
김영한 강사님의 강의를 듣고 리뷰한 포스팅을 많이 참고했는데 강의가 굉장히 알고 쉽고 퀄리티가 높을 뿐더러 내가 필요로 했던 CS 지식도 커리큘럼에 포함되어 있어 네트워크와 HTTP에 대한 포스팅 이후 강의를 들어볼 생각이다.
IP
인터넷은 수많은 중간 노드(서버)들이 혼재한 상태이고 우리는 그 노드들을 통해 클라이언트-서버 간의 연결을 수행해야 한다.
IP(Internet Protocol)는 이 때 각 클라이언트와 서버에 도달하기 위한 주소의 역할을 한다. IP에서 각각의 클라이언트와 서버는 각자의 IP 주소를 가지고, 데이터를 패킷 단위로 가공하여 지정된 IP 주소에 전달한다.
패킷은 헤더와 내부 데이터로 나뉘는데, 헤더에 출발지의 IP, 도착지의 IP 등을 담고 데이터 파트엔 전송할 데이터를 담아 보내진다.
IP에서는 이렇게 만든 패킷을 많은 중간 노드들을 거쳐 전송하게 되는데, 대상 서버가 제대로 작동 중인지 확인할 방법이 없고(비연결성), 중간 노드에서 문제가 생겨 패킷이 소실되어도 알 방법이 없고 패킷 순서가 보장되지 않는 등(비신뢰성), 여러 문제점이 존재한다.
해당 문제점들을 해결하기 위해 나온 새로운 프로토콜이 TCP이다.
TCP
TCP에서는 OS의 TCP 계층이 추가되어, 패킷을 생성하기 이전에 OS의 TCP 계층에서 TCP 정보를 만들고, 이를 포함하여 패킷이 생성된다.
TCP 정보에는 출발지 PORT, 도착지 PORT, 전송 제어, 순서 등의 정보들이 담겨있다.
TCP는 서버와 연결될 때 3-way handshake이라 불리는 3단계의 방식을 통해 논리적 연결을 구성한다. 그 과정은
- 클라이언트가 서버에 접속을 요구하는 SYN을 보냄.
- 서버에서 SYN을 받고, 클라이언트에 접속을 요구하는 SYN과 함께 요청 수락을 의미하는 ACK을 보냄.
- 클라이언트에서 SYN을 받고, 서버로 ACK을 보냄.
이렇게 3단계 과정을 거쳐 생성된 연결은, 클라이언트가 데이터를 보내면 서버가 응답하고, 정해진 패킷 순서대로 패킷이 전달되지 않으면 서버가 클라이언트에 재전송을 요구하는 등 IP의 여러 문제점이 해결되어 신뢰성이 높아진다.
UDP
보통 TCP는 전화로, UDP는 택배로 비유된다. UDP는 연결 없이 목적지를 향해 데이터를 일방적으로 발송하는 방식으로, Datagram으로 데이터를 가공하기 때문에 데이터 간의 경계가 명확하다.
하지만 연결이 없기 때문에 IP와 유사하게 비신뢰성, 비연결성의 문제가 발생한다. 그럼에도 속도가 TCP보다 빠르기에 연결의 신뢰성보다 속도가 우선시되는 실시간 스트리밍 등의 용도로 사용된다.
PORT
위에서 배웠다시피 클라이언트와 서버는 각자의 IP주소를 가진다. 그런데 만약 클라이언트가 게임, 영상, 채팅의 3가지 어플리케이션을 통해 3번의 연결을 한다면, 클라이언트의 IP주소로 도착한 패킷들이 어떻게 각 어플리케이션을 구분할 수 있을까?
이러한 문제를 해결하기 위해 나온 것이 PORT이다. TCP/IP 구조에선 헤더에 출발지 PORT, 도착지 PORT 등이 추가로 들어가던 것을 기억할 것이다. 같은 IP로 들어가더라도 어플리케이션에 따라 PORT 주소가 다르기에 어플리케이션을 구분하여 연결하는 것이 가능하다.
PORT는 0~65535번까지 할당이 가능하고, 0~1023까지는 잘 알려진 번호이므로 사용하지 않는 것이 좋다.
DNS
기본적으로 IP주소는 변경이 가능하다. 그러므로 기존과는 IP주소가 달라져 연결이 제대로 이루어지지 않는 경우가 발생할 수 있다. 또한 10자리가 넘는 숫자이므로 기억하기가 어렵다.
그렇기 때문에 우리는 DNS(Domain Name System)을 사용한다. DNS를 통해서는 IP에 이름(도메인)을 붙일 수 있기 때문에 기억하기 쉬운 도메인만 알고 있다면 IP가 변경되어도 쉽게 접근할 수 있다.
URI
URI(Uniform Resource Identifier)는 웹 상에서 자원에 접근하기 위한 식별방식이다. URI에는 위치를 나타내는 URL과 이름을 나타내는 URN이 있는데, URN은 방법이 보편화되지 않아 거의 쓰이지 않으므로 URI는 URL과 동의어라고 생각하면 된다. URL의 문법은 다음과 같다.
scheme://[userinfo@]host[:port][/path][?query][#fragment]
- scheme : 주로 https 등의 프로토콜이 들어간다.
- userinfo : 사용자 정보를 넣어 인증하는 방식으로 거의 사용되지 않는다.
- host : 도메인명, 또는 IP 주소를 사용한다.
- PORT : PORT 번호로 일반적으로는 생략한다.
- path : 해당 웹의 계층적 구조를 입력한다.
- query : 해당 웹 서버에서 제공하는 문자 형태의 파라미터로 key-value 형태이다. ?로 시작하고 &로 추가한다.
- fragment : html 내부 북마크 등에 사용하는 정보로 서버에는 전송되지 않는다.
웹의 요청 방식
그럼 지금까지 배운 것을 정리하여 웹에서 서버에 무언가를 요청했을 때, 구체적으로는 URL을 브라우저에 입력했을 때 어떤 일이 일어나는지를 순서대로 알아보자.
- 웹 브라우저에 URL을 입력한다.
- DNS를 통해 IP 주소를 얻어오고, PORT는 생략되어 있다면 프로토콜(https)을 보고 추론한다.
- 이렇게 얻은 IP 주소와 PORT로 HTTP 요청 메세지를 작성한다. http 메서드/path, query string/HTTP 버전/호스트(도메인명) 와 같은 구조이다.
- 헤더 부분에 IP와 PORT 주소를 넣어(이 때 데이터는 비어있다) 만든 패킷으로 3-way-handshake를 실행하여 서버와 연결한다.
- 연결이 완료되면 HTTP 메시지를 OS의 TCP/IP 계층에 내려보내 데이터 부분에 메시지가 담긴 TCP/IP 패킷을 생성한다.
- TCP/IP 패킷이 수많은 중간 노드를 거쳐 서버로 전달된다.
- 패킷을 받은 서버는 헤더를 제외하고 데이터 부분의 메시지를 해석한 후 HTTP 응답 메시지를 작성한다.
- 서버에서 똑같이 TCP/IP 패킷을 작성하여 클라이언트로 전달한다.
- 웹 브라우저가 응답 패킷에서 헤더를 제외한 메시지 부분을 해석하여 렌더링한 후 화면에 출력한다.
지금까지 웹의 기본적인 프로토콜과 작동 방식에 대하여 알아보았다. 다음 포스팅에서는 가장 많이 사용되는 HTTP 프로토콜에 대해 알아보도록 하겠다.