CS/네트워크

[네트워크] 3. Transport layer (1) - UDP/TCP, RDT, multiplexing, flow control, congestion control, 3-way handshake

공영재 2023. 10. 14. 03:20

Reference - Computer Networking: a Top Down Approach

 

 

Transport layer는 Application의 end to end (source와 destination)을 연결시켜주는 역할을 하는 layer다.

 

UDP, TCP

Application layer와 transport layer 사이를 통신함에 있어 Socket이 필요하다.

앞서 언급했듯이 socket은 두 layer를 통신하게 해주는 문과 같은 역할이라 생각하면 편하다.

 

Socket은 두가지 방식이 있는데, UDP와 TCP이다. 참고로 Transport layer에서 패킷을 UDP는 datagram, TCP는 segment라 칭하니 기억해두자. 먼저 UDP에 대해 살펴보겠다.

 

UDP (User Datagram Protocol)

 

UDP socket은 unreliable / unordered / connectionless 의 특징을 갖는다.

UDP는 TCP처럼 handshake 과정이 없어 연결을 보장하지 않는다.  또한 TCP와 달리 데이터 전송 간 loss가 발생할 수 있고, 패킷별 네트워크 경로에 따라 도착 순서가 바뀔 수 있다. 이는 best-effort, 최대한 되게 하는 방식으로 동작하게끔 설계된 것이고 위 내용을 보장한다는 것을 의미하지는 않는다. 하지만 TCP에 비해 단순해 속도가 빠르다. 손실에 둔감하고 빠른 속도를 요구하는 app에 요구된다.

 

UDP의 실행과정은 아래와 같다.

1. server가 특정 port로 socket을 연다(=create socket).

2.  client도 socket을 만든다. 그 뒤, client가 server IP와 port number가 들어간 datagram을 만든다. clientSocket을 통해 datagram을 보낸다.

3. serverSocket을 통해 받은 datagram을 읽는다.

4. server가 client address, port number를 포함한 reply를 만들어서 serverSocket을 통해 보낸다.

5. clientSocket을 통해 받은 datagram을 읽는다.

6. clientSocket을 닫는다.

 

UDP는 checksum이라는 segment header를 갖고 있는데, 에러를 탐지할 수 있다. 수정은 불가하다.

16-bit integer를 flip하여, 원본 데이터 bit와 더하는 방식으로 데이터 손상을 탐지하는 시스템이다.

 

UDP는 loss에 tolerant하고 rate sensitive한 DNS, streaming multimedia app 등에 용이하다. 하지만 특정 application이 반드시 특정 protocol을 가지는 것은 아니며, 설계에 따라 다른 protocol을 가질 수도 있다.

 

TCP (Transmission Control Protocol)

 

TCP는 UDP와 다르게 reliable, 신뢰할 수 있다고 한다.

그 말인 즉슨 데이터의 전송 순서를 보장한다는 의미이다. 또한 TCP는 handshake 과정을 통해 연결을 확인한다.

 

TCP의 실행과정은 아래와 같다.

 

1. server에서 특정 port로 TCP socket을 연다. 그 뒤 server는 connecion request를 기다린다.

2. client에서 TCP socket을 열고, hostid와 port number로 연결한다.

3. client가 request를 보내고, serverSocket이 이를 읽는다.

4. serverSocket이 reply를 작성하여 clientSocket에 보내고, clientSocket이 이를 받아 읽는다.

5. server와 client는 각각의 socket을 닫는다.

 

 

Transport layer는 다른 두 호스트의 app process 간 논리적 통신을 제공한다.

Network layer와의 차이점은 

전송할 데이터가 올바르게 목적지에 도착했는지 확인한다.

network layer는 end to end에서 경로 상의 단말(라우터)간 효율에 대한 계층이고,

transport layer는 end to end의 데이터가 잘 전송하고 도착했는지에 대한 계층이다.

 

transport layer service에 4가지 키포인트가 있다. 각각에 대해 차차 알아보겠다.

1. multiplexing and demultiplexing

2. reliable data transfer

3. flow control

4. congestion control

 

Multiplexing and Demultiplexing

 

transport layer에서 sender가 socket들에게서 데이터를 모으고 transport header를 붙이는 것을 multiplexing,

receiver가 header를 통해 segments를 잘 모아서 알맞은 socket에 보내는 걸 demultiplexing이라 한다.

 

소켓은 유일한 식별자인 포트 번호를 갖고, 각 세그먼트는 전달될 적절한 소켓(포트번호)을 가리키는 필드를 갖는다.

 

UDP 소켓의 경우 destination IP와 destination port number로 식별된다.

source port number는 회신에 사용된다.

 

TCP 소켓의 경우 4개 요소의 집합(source IP, source port num, dest IP, dest port num)로 식별된다.

서버는 각각의 client에 대해 다른 소켓을 가지고 있다. (단, port number는 같을 수 있다. 이는 socket 요소 쌍(source IP, etc.)이 다르기에 가능하다.)

 

RDT (Reliable Data Transfer)

 

RDT의 역할은 "1. 전송된 데이터가 손상/손실되지 않고 2. 전송된 순서대로 전달"되는 신뢰적인 채널을 추상화하는 것이다. 이때의 state를 표현하는 방법으로 FSM (Finite-state machine)이 있다.

분자는 event, 분모는 event에 따른 action이다. 

 

 

RDT는 1.0부터 시작하여 여러 issue로 인해 3.0까지 upgrade된다. 하나하나 알아보겠다.

 

RDT 1.0은 하위 채널이 완전히 신뢰적인 경우다.

이때 sender는 rdt_send 이벤트가 발생하면 packet을 생성하고 udt_send를 통해 채널로 송신한다.

그 뒤 receiver에게 rdt_rcv 이벤트가 발생하면 패킷을 데이터로 추출하고 상위 계층으로 데이터를 전달한다. RDT 1.0의 FSM은 아래와 같다.

 

 

하지만 채널이 항상 reliable하진 않기때문에 RDT 2.0이 등장하였다.

 

RDT 2.0은 채널이 bit error를 발생시키는 경우다. 위에서 설명한 checksum을 통해 error를 탐지한다.

이때 ACK와 NAK이라는 개념이 등장한다. Acknowledgements와 negative acknowledgements의 약자로, receiver가 데이터를 제대로 받았으면 ACK, 그렇지 않으면 NAK를 회신하는 방식으로 control한다.

NAK를 회신받았을 경우 packet retransmission을 요청한다. RDT 2.0의 FSM은 아래와 같다.

 

 

 

error의 유무에 따라 receiver가 corrupt인지 notcorrupt인지 판단하고 의사결정을 한다.

RDT 2.0은 ACK/NAK 자체가 corrupt됐을 때 handling하지 못한다는 문제가 있다. 이를 해결하기 위해 RDT 2.1이 등장했다.

 

RDT 2.1은 패킷에 시퀀스(0, 1)을 추가하여 패킷을 구분한다.

#0 패킷을 보낸뒤 receiver에게서 #0 ACK를 받으면 #1 패킷을 전송한다. #0 NAK나 corrupt가 생기면 sender가 #0 패킷을 재전송한다. receiver가 duplicate packet을 받으면 기존 데이터를 지우고 #0 ACK를 회신한다. 시퀀스를 0, 1만 쓰는 이유는 보내는 패킷이 재전송 패킷인지 다음 패킷인지 구별하는 최소한의 수만 있으면 되기 때문. 

 

 

RDT 2.2는 위에서 NAK없이 ACK로만 구현한다. 에러가 있으면 다른 시퀀스번호를 보내 NAK를 대신한다.

 

RDT 3.0은 데이터의 에러뿐만아니라 loss까지 고려한다. 이를 위해 sender가 전송하고 일정 시간 대기한 뒤 ACK가 없으면 재전송한다. ack를 받기 전에 timeout 되어 재전송을 한다면 packet이 duplicate되지만, 해당 문제는 시퀀스로 해결한다.

send 후 receiver로부터 #0 ACK가 아닌 다른 값이 오면 Timeout이 끝날때까지 기다리다 다시 packet을 보낸다.

이를 구현하기 위해 countdown timer가 필요하다. timer는 매 패킷이 송신될 때 시작하고, action을 하면 멈춘다.

 

 

RDT 3.0: Stop-and-Wait Operation

 

RDT 3.0은 패킷이나 ACK를 전송하면 응답이 올 때까지 멈추고 기다린다. 이때문에 RTT가 길수록 성능 이슈가 생긴다. 

 

 

이 문제를 해결하기 위해 여러개의 패킷을 같이 보내는 pipeline protocol이 있다. RTT가 매우 크다고 가정하면, n개의 패킷을 같이 보낼수록 Utility는 n배에 가까워 진다. 이때 보낼 수 있는 패킷의 수를 window size라 한다. 또한 이를 구현하기 위해 패킷 수만큼의 시퀀스가 필요하고, sender와 receiver에 reply(ACK, NAK)받지 않은 패킷을 저장할 버퍼가 필요하다.

이제 이를 구현하는 두 프로토콜, Go Back-N과 Selective repeat에 대해 살펴보겠다.

 

Go-Back-N

 

Go-Back-N은 sender가 N개의 packet을 파이프라인으로 보낼 수 있는데, receiver는 packet에 gap이 있으면 최근에 성공적으로 받은 패킷 시퀀스에 해당하는 #ACK를 reply한다. sender는 duplicate ACK를 무시하다가, timeout이 되면 그때 다시 ACK을 못받은 packet부터 retransmit한다. 그 과정은 아래와 같다.

 

 

Selective Repeat

 

Selective Repeat은 마찬가지로 N개의 packet을 보내는데, receiver는 packet에 gap이 있으면 buffer에 잠시 저장하고 그대로 #ACK을 보낸다. sender도 마찬가지로 gap이 있는 ACK를 받으면 buffer에 저장하고, ACK을 못받은 #packet이 timeout이 되면 해당 패킷을 보낸다. 이때 receiver는 해당 packet이 도착하면 buffer에 저장해둔 그다음 시퀀스 패킷도 모두 상위 계층에 deliver한다. 그 뒤 sender가 손실됐던 ACK를 받으면, sender도 buffer에 ACK를 기억해뒀으므로 마지막 ACK의 다음 sequence 패킷부터 전송을 재개한다. 그 과정은 아래와 같고, 그림의 질문에선 pkt6을 send하게 될 것이다.

 

Selective Repeat: Dilemma

 

Selective Repeat에는 두 딜레마가 존재한다.

한정된 패킷 시퀀스를 사용할 때 패킷이 손실되는 경우와 ACK가 손실되는 경우다.

패킷이 window size-1의 sequence가 손실되어  손실되는 경우

 

Throughput Analysis

 

세 과정의 throughput을 살펴보면, 복잡한 증명과정(생략)을 거쳐 아래의 수식이 도출된다.

 

 

p는 패킷이 성공적으로 전송될 확률, alpha는 RTT를 의미한다. 위 수식은 곧 RDT pipeline protocol이 performance와 complexity가 tradeoff임을 의미한다.

 

TCP Overview

TCP 특징

 

- point to point : one sender, one receiver

- reliable, in-order byte stream : 데이터 송수신간 loss가 없고 순서가 지켜진다.

- pipelined : window size를 통해 sequence가 붙은 n개 데이터씩 송수신한다. -> 그렇기에 congestion이 발생할 수 있고 flow control이 필요하다.

- full duplex data : 연결이 되면 양방향 통신이 가능하다.

- connection oriented : handshaking 과정이 있다.

- flow controlled : buffer 잔여량을 알려줘서 sender의 sending rate를 control할 수 있다.

 

Timeout - 패킷 loss를 retransmittion하기 위해 필요하다.

Timeout만 기다리기엔 너무 오래걸려 TCP 성능이 떨어진다 -> duplicate acks을 받을 시 Fast retransmit이 가능해진다.

Timeout 설정을 위한 estimated RTT = (1-a)*estimatedRTT + a*sampleRTT (a=generally 0.125)

 

Flow control

 

receiver가 sender에게 buffer 잔여량을 RWND를 통해, 전체 rcvBuffer size를 handshake를 통해 알려줘서 sender가 receiver의 buffer가 overflow되지 않게 sending rate를 control하게 한다.

 

Congestion control

 

보내야 될 패킷이 라우터/리시버 등의 큐에 너무 많이 쌓여있을 때 이를 sender에게 알려 sending rate를 control하는 것을 말한다. => CWND(송신자가 보낼 수 있는 segment 크기) 사용

ACK clocking : ACK이 늦게 돌아오면 네트워크가 혼잡한 상태라 판단하고, ACK가 빨리오면 네트워크가 여유롭다 판단한다.

 

TCP 3-way handshake

 

2-way handshake : sender ->(1) receiver ->(2) sender. 단점: sender와 receiver가 서로의 상황을 모른다. 즉, sender가 보내는 동안 time difference로 인해 sender의 상황이 달라졌을 때(ex. timeout) receiver가 이를 알아차리지 못해 문제가 발생할 수 있다. 아래가 그 예시다.

 

 

위 오른쪽 그림과 같이, receiver의 reply가 늦어 sender가 timeout이 되고 x를 다시 보냈을 때, server는 이미 timeout으로 x에 대한 정보를 잊은 후라 x와 x+1이 헷갈리게 된다.

 

3-way handshake :  sender ->(1) receiver ->(2) sender ->(3) receiver

 

TCP 연결시에는 SYNbit, TCP를 끊을 때는 FINbit을 사용한다. 각각 SYNbit과 FINbit에 해당하는 ACKbit을 받는 순간, 연결을 시작하거나 끊는다.

loading