본문 바로가기
Computer Science/Network

[네트워크] "www.google.com"을 입력하면 어떻게 되나? 6편 TCP

by whatamigonnabe 2022. 8. 13.

 

이전 글

[네트워크] "www.google.com"을 입력하면 어떻게 되나? 5편 HTTP

[네트워크] "www.google.com"을 입력하면 어떻게 되나? 4편 SSL (TLS)

 

[네트워크] "www.google.com"을 입력하면 어떻게 되나? 3편 Port(포트), Socket(소켓)

[네트워크] "www.google.com"을 입력하면 어떻게 되나? 2편 DNS

[네트워크] "www.google.com"을 입력하면 어떻게 되나? 1편 - LAN/WAN, TCP/IP 4 계층, 패킷 교환 방식

 

어느새 6편을 쓰게 됐습니다. 제가 정리한 깊이도 얕지만, 처음엔 더 얕게 생각해서 더 짧게 끝날 줄 알았어요.. 파면 팔 수록 끝없이 나오고, 더 어려워지는 것 같습니다. 그래도 이렇게 복잡한 약속들을 전세계 사람들이 공유하고 있다는 것이 너무 신기하고 재밌는 것 같아요.

 

아무튼 지난 편까지, 서버측과 연결을 하고 암호화 방법을 공유하고 그리고 Application Layer의 HTTP의 Request 메시지까지 만들어봤습니다. 이제 이 메시지를 그 아래 계층인 Transport Layer의 TCP로 넘겨줄 차례입니다.

 

TCP

Transport Layer: 포트를 이용해 특정 응용 계층의 프토코콜로 전달, 패킷을 운영

우선 TCP가 무엇인지 살펴보기 전에, Transport Layer에 대해 잠깐 알아보겠습니다. 이 계층은 응용 계층으로 정보를 '잘' 전달하는 역할을 합니다. 지난 편에서 살펴봤듯이, 응용계층의 프로토콜을 사용하는 프로세스들은 각각 포트 번호를 가지고 있습니다. IP는 컴퓨터를 식별하고, 하나의 컴퓨터 안에서 동작하는 여러 프로세스들 중 하나를 식별하기 위해서는 이 포트 번호가 필요하죠. 그래서 Transport Layer에서는 이 '포트'를 이용해서 통신하고자하는 응용 계층의 특정 프로세스로 정보를 전달합니다.

 

또한 지이이난 1편에서 살펴봤듯이, 네트워크 통신에는 주로 '패킷 교환 방식'이 사용됩니다. 바로 이 Transport Layer에서 Application Layer에서 보내고자하는 데이터를 패킷으로 분해하고, 다시 조합하는 역할을 담당합니다. 사실 이 계층에서 다루는 데이터가 정확히 패킷은 아니고 Segment입니다. 아래 표를 참고하세요.

계층 데이터의 단위
Application Layer Data / Message
Transport Layer Segment
Internet Layer Packet
Network Access Layer Frame

그런데 이 세그먼트를 다루는 방법에 있어서 대표적으로 두 개의 프로토콜이 있습니다. 하나는 우리가 사용할 TCP이고, 다른 하나는 UDP입니다. 데이터의 신뢰성이 중요할 때는 TCP를, 속도가 중요할 때는 UDP를 사용합니다.

TCP (Transmission Control Protocol)

TCP는 이름에도 나와있는 것처럼 'Cotrol'이 주된 역할을 합니다. 패킷 교환 방식을 사용하면, 도착지까지 패킷이 이동할 때 어떤 루트를 이용할지 알 수 없습니다. 보내는 상황에 따라 최적의 루트를 선택하게 되기 때문입니다. 그런데 문제는 이게 패킷별로 달라진다는 것입니다. 먼저 보낸 패킷이더라도 이 패킷이 멀리 돌아가는 루트를 선택했다면 뒤에 보낸 패킷 보다 늦게 도착할 수도 있고, 심지어 유실될 수도 있습니다. 

 

이런 패킷 교환 방식의 데이터 신뢰성에 대한 문제를 해결하는 것이 TCP입니다. TCP는 패킷이 도착하면 순서가 제대로 됐는지 확인하고 다를 경우 원래의 순서로 맞춥니다. 그리고 만약에 빠진 패킷이 있다면 송신측에 알려 다시 보내달라고 요청해서 받아오기도 합니다.

 

어떻게 이런 기능을 수행할 수 있을까요? TCP의 작동과정을 따라가며 이해해보겠습니다.

 

 

연결 (3 way handshake)

서버도 클라이언트도 동시에 여러 다른 상대와 송수신을 하는데, 큰 데이터를 작은 여러 개의 패킷으로 나눠서 보냅니다. 도착하는 패킷들을 송신자에 따라 분리해서 보관했다가 순서를 맞출 필요가 있습니다. 또 빠진 것이 있다면 그 송신자에게 다시 요청해야하죠. 그래서 통신을 수행하는 당사자 간의 1대1 연결을 할 필요가 있습니다. 그래서 우리는 TCP 소켓 연결을 진행하는 것이고, 그래서 TCP는 '연결지향'이라고 불립니다. 

 

구체적인 연결 과정은 이전 글을 참고해주세요.

[네트워크] "www.google.com"을 입력하면 어떻게 되나? 3편 Port(포트), Socket(소켓)

 

데이터 분해

데이터를 본격적으로 보내기 전에 응용 계층에서 만든 메시지를 작은 데이터 단위로 나눠야합니다. 하나의 데이터가 송신측에서 수신측까지 도달하기 위해  다수의 네트워크 장비(라우터)를 거치게 됩니다. 그리고 이 장비들 각각 한번에 최대로 수용할 수 있는 데이터 크기가 다르죠. 그래서 3-way-handshake를 진행하면서 거치는 라우터들의 수용가능한 최대 데이터 크기를 파악한 후 가장 작은 사이즈로 자르게 됩니다. 이때 수용 가능한 가장 큰 데이터의 크기를 MTU(: Maximum Transfer Unit)이라고 합니다. 

 

조금만 더 자세히 알아본다면, 응용 계층에서 넘어온 데이터를 MSS(Maximum Segment Unit)으로 자릅니다. MSS는 MTU에서 각종 헤더를 뺀 크기입니다. 최종적으로 메시지를 잘게 자른 것에 헤더를 붙여서 전송을 하게 되고, 그것이 MTU가 되는 것입니다.

그리고 이렇게 데이터를 분해할 때 데이터의 순서를 각 세그먼트에 기록해두고, 수신측에서 이것을 보고 순서를 다시 맞추는 것입니다.

아래의 TCP 헤더를 보면, 'Sequence number'가 바로 순서를 나타내는 숫자입니다. 이 숫자를 0으로 초기화했다면, 첫번째 세그먼트의 Sequence number가 0, 그 다음이 0 + MSS, 그 다음이 (0 + MSS + MSS) 식으로 설정하게 됩니다.

출처: https://ko.wikipedia.org/wiki/전송_제어_프로토콜

 

흐름 제어

순서를 파악하는 방법은 알았는데, 중간에 유실된 패킷을 어떻게 확인할까요? 수신측에서 데이터를 받을 때마다 위에서 살펴본 'Sequence number'를 보고 1을 더해 'Ackknowledgment number'에 담아서 보냄으로서 '잘 받았다'라는 응답을 계속 보내는 방법을 사용합니다. 송신측에서 수신측의 'ack' 패킷을 받지 못하면 다시 해당 패킷을 보내게 돼죠. 이 과정을 통해 데이터의 신뢰성을 얻고 통신의 속도를 잃게 됩니다.

 

그런데 매 패킷바다 이런 통신을 교환하면 속도가 너무 느려질 것입니다. 그래서 이용하는 것이 'Window Size'입니다. 수신측에 UDP는 별도의 버퍼 공간을 가지고 있습니다. 위에서 언급한 것처럼 수신자별로 저장해놨다가 다시 순서를 맞춘 후 응용 계층에 넘겨줄 때 필요하기 때문입니다.(제 생각엔 그렇습니다ㅎㅎ) 이 공간의 사이즈가 Window size이고, 수신측에서 이 사이즈가 가득 찰 때까지 기다렸다가 ack패킷을 보내는 방식을 사용하여 속도를 개선합니다. 이것을 흐름제어라고 합니다. 

 

UDP(User Datagram Protocol)

지금까지 TCP에 대해 알아보았습니다. 이것은 연결지향이고, 데이터의 순서와 유실을 방지함으로써 통신의 신뢰성을 보장합니다. 하지만, 이러한 기능 때문에 속도가 느리다는 단점이 있습니다. 그리고 때에 따라 데이터의 신뢰성보다는 속도가 중요한 경우가 있죠. 대표적으로 실시간 스트리밍이 될 것입니다. 이럴 때에는 TCP를 사용합니다. 

 

TCP는 위에서 설명한 기능이 전혀 없습니다. 따라서 비연결지향이고, 데이터의 순서와 유실을 방치(?)합니다. 덕분에 속도가 매우 빠르죠. TCP헤더를 보면 훨씬 단순합니다. 오고 가는 포트번호, 세그먼트의 길이, 그리고 에러를 체크하는 Checksum만 있습니다. 데이터의 순서를 확인하는 기능이 없기 때문에, 필요하다면 어플리케이션에서 설계해야합니다.

출처: https://en.wikipedia.org/wiki/User_Datagram_Protocol

다시 구글 서버로,,,

자, 그럼 다시 구글 서버로 가볼까요? 응용계층에서 만든 메시지를 지금까지 알아본 TCP에 따라 여러 작은 데이터로 쪼갠 뒤 TCP헤더를 붙이게 됩니다.

출처: https://ko.wikipedia.org/wiki/전송_제어_프로토콜

TCP헤더에서 중요하게 볼 부분은 세 가지 인 것 같습니다. Source port는 송신측의 포트번호로 임의의 번호가 될 것이고, Destination port는 https를 사용하니 433일 것입니다. 그리고 세그멘트별로 Sequence number가 붙을 것입니다. 

 

이렇게 만든 TCP Segment는 이제 Internet Layer로 넘어가 IP를 만날 것입니다.

 

 

참조

https://blog.naver.com/sung_mk1919/221435640417

https://better-together.tistory.com/140