CS 공부/네트워크

Chapter 3 - Transport Layer(2)

3.5 Connection-oriented transport : TCP

TCP Overview

  • point-to-point : 송신자, 수신자가 서로 1대 1로 데이터를 주고받는다.
  • 신뢰적이며, 데이터가 큰 파일을 byte stream으로 나누어 보낸다.
  • 파이프라인화 되어있다.
  • 양방향 연결 서비스를 제공한다.
  • 혼잡 제어, 흐름 제어 기능을 가지고 있다.
  • 3-way 핸드 셰이크를 사용해 연결 지향적이다.

 

TCP Overview : segment structure

 

src, dst 포트 번호와 데이터 길이, 체크섬, 데이터만 가지고 있는 UDP 헤더와 다르게

위 그림에서 보다시피 상당히 많은 것들이 TCP 헤더에 담겨 있다.

 

  • 연결 지향으로 sequence num, ack num들이 무려 32비트를 차지한다.
  • head len에는 헤더만의 길이만 저장한다.
  • U, A, P, R, S, F는 헤더를 표시한다.

 

TCP의 시퀀스, ack 넘버

1) 시퀀스 넘버 : 첫 번째 세그먼트의 바이트 넘버를 의미한다.

2) ack 넘버 : 다음으로 받고자 하는 시퀀스 넘버를 의미하고, 이는 누적 ack이다.

 

위 그림처럼 각각 호스트 A, B가 tcp 전송을 하고, 양방향으로 둘 다 sender와 receiver의 역할을 한다.

 

A가 시퀀스 42, ACK 79를 보내면, B는 그에 대한 응답으로 시퀀스 79와 ack 43을 요청한다.

 

 

Reliable data transfer

TCP는 IP의 비신뢰적인 'best-effort' 서비스에서 신뢰적인 데이터 전달 서비스를 제공한다.

 

TCP의 신뢰적인 데이터 전달 서비스는 프로세스가 자신의 수신 버퍼로부터 읽은 데이터 스트림이

손상되지 않았으며 손실이나 중복이 없다는 것과 순서가 유지된다는 것을 보장한다.

 

 

TCP sender events

TCP 송신자의 이벤트

  • 시퀀스 넘버와 함께 세그먼트를 만든다.
  • 시퀀스 넘버는 첫 번째 데이터 바이트의 바이트 스트림 넘버이다.
  • 가장 오래된 세그먼트에 대해 타이머를 작동시킨다.(아직 ack 받지 못한 세그먼트 중)
  • 앞의 ack가 도착 시 ack를 업데이트한다.

 

TCP sender의 FSM이다.

순서를 설명하자면

  1. 시퀀스 넘버, sendbase를 초기화한다. (둘 다 동일)
  2. 이벤트에 대해 기다린다.
  3. 애플리케이션 계층에서 데이터를 수신받으면, 세그먼트(+시퀀스 넘버)를 생성 후 다음 시퀀스 넘버를 만들고, 타이머를 시작한다.
  4. if timeout : 아직 ack 되지 않은 세그먼트들 중 가장 시퀀스 넘버가 낮은 세그먼트를 재전송 후 타이머를 시작한다.
  5. ack를 받았을 경우, 만약 그 ack가 맨 앞이 아닐 때, sendbase를 거기까지 껑충 올린 후, 아직 ack를 받지 못한 segment가 없을때 타이머를 중지한다.

5번의 경우에 대한 그림이다.

92번 시퀀스 넘버에 대한 응답을 받지 못했지만, 120 ack에 의해 타이머를 멈추었기 때문에 에러가 발생하지 않는다.

 

 

TCP ACK 생성 권고

생성 권고는 (1) 이벤트에 따른 (2) 행동을 정한 내용이다.

 

1) 기다리는 순서 번호를 가진 순서가 맞는 세그먼트의 도착. 기다리는 순서번호까지의 모든 데이터들은 이미 확인 응답

-> 지연된 ACK. 또 다른 순서가 맞는 세그먼트의 도착을 위해 500ms 기다린 후, 도착하지 않으면 ACK를 보낸다.

 

2) 기다리는 순서번호를 가진 순서가 맞는 세그먼트의 도착. ACK 전송을 기다리는 다른 하나의 순서에 맞는 세그먼트가 있음 

-> 즉시 2개의 순서가 맞는 세그먼트들을 ACK 하기 위해 하나의 누적된 ACK를 보낸다.

 

3) 기다리는 것보다 높은 순서 번호를 가진 순서가 틀린 세그먼트의 도착. 격차가 발견됨

-> 즉시 순서 번호가 다음의 기다리는 바이트를 나타내는 중복 ACK를 보낸다.

 

4) 수신 데이터에서 격차를 부분적으로 또는 모두 채우는 세그먼트의 도착

->즉시 ACK를 보낸다. 단, 가장 낮은 쪽까지 진행.

 

 

 TCP fast retransmit

타임아웃의 기간은 종종 꽤 길기 때문에 더 빠르게 할 방법이 필요하다.

다행히도 그런 방법이 존재하는데, 바로 중복 ACK가 수신된 경우이다.

 

기존의 방법에서는 중복 ACK를 받더라도 타임아웃이 날 때까지 기다리는 방법을 선택했다면,

tcp의 빠른 재전송은 3개의 중복 ack를 받으면 타임아웃을 기다리지 않고 바로 재전송을 요구하게 된다.

 

 

Flow Control

흐름 제어의 개념은 아주 간단하게 말해, 송신자가 전송하는 속도가 수신자의 수신하는 속도보다 낮거나 같게 하는 것을 말한다. 만약 반대의 상황이라면 수신 버퍼에 오버플로우를 발생시킬 수 있기 때문이다.

 

TCP에서 송신자는 수신 윈도라는 변수를 유지하여 흐름 제어를 제공하게 된다.

 

수신 윈도는 수신 측에서 가용한 버퍼 공간이 얼마나 되는지를 송신자에게 알려주는 데 사용된다. 

TCP는 양방향성을 갖고 있기 때문에, 각각의 송신자는 별개의 수신 윈도를 유지한다.

 

변수 정의

  • RcvBuffer : 할당된 수신 버퍼의 크기
  • LastByteRead : 수신자의 애플리케이션 프로세스에 의해서 버퍼로부터 읽힌 데이터 스트림의 마지막 바이트 수
  • LastByteRcvd : 수신자의 네트워크로부터 도착하여 수신 버퍼에 저장된 데이터 스트림의 마지막 바이트 수
  • rwnd : 수신 윈도로, 버퍼의 여유 공간으로 설정된다.

 

  • sender ->  in-flight data = LastByteSent - LastByteAcked
  • receiver -> rwnd = rcvbuffer - (LastByteRcvd - LastByteRead)

 

Connection Management

이번에는 TCP 연결이 어떻게 설정되고 해제되는지 더 자세히 살펴보자.

송수신자는 "핸드 셰이크"라는 과정을 거치고 송수신을 하게된다.

 

3Way handshake

1단계 : 클라이언트 TCP는 서버 TCP에게 특별한 TCP 세그먼트를 송신한다. 이 세그먼트 헤더 안에는 SYN 비트라고 불리는 하나의 플래그 비트를 가진다. 추가적으로 클라이언트는 초기 시퀀스 넘버를 필드에 저장한다. 아직 데이터는 없다.

 

2단계 : 서버에 SYN이 도착했을 때, 서버는 SYNACK 세그먼트(연결 승인)를 보낸다. 이때, 서버는 SYN flag, ACK flag, ack num, sequence num을 초기화한다. ACK num은 client가 보낸 seq num +1로 설정된다.

 

3단계 : 연결 승인 세그먼트를 수신하면, 클라이언트는 연결에 버퍼와 변수들을 할당한다. 그다음 클라이언트 호스트는 서버로 또 다른 세그먼트를 송신한다. 이때 연결이 설정되었기 때문에 SYN 비트는 0으로 설정되며, 이때부턴 데이터를 보낼 수 있게 된다.

 

과정에 대한 그림은 다음과 같다.

4.1 연결 해제

 

이번엔 클라이언트가 연결 종료를 희망한다고 해보자. (보통 TCP 서버는 항상 열려있기 때문에, 클라이언트가 먼저 시작합니다!)

 

 

클라이언트 TCP는 먼저 1로 설정된 FIN 비트를 포함하는 TCP 세그먼트를 송신하도록 하고, 기다린다.

이후 서버 TCP는 확인 응답 비트를 보낸 후 현재 보내고 있는 데이터들을 마무리 짓는다.

이후 마무리를 지었다는 FIN 비트를 서버가 보냈을 때, 클라이언트는 확인 응답 비트를 보내고 연결을 종료한다.

 

3.6. principles of congestion control (혼잡 제어의 원리)

TCP가 어떻게 혼잡 제어를 하는가? 에 대해 알아보기에 앞서, 혼잡 제어가 무엇이고 어떤 상황이 발생할 수 있는지 먼저 알아보도록 하겠다. 바로 위에서 다뤘던 flow control과 congestion control과 비슷해보이지만 다르다. 

 

혼잡이란?

혼잡이란 네트워크가 감당하기에는 많은 송신자가 너무 많은 패킷을 너무 빠르게 보내 발생하는 현상을 의미한다.

이는 흐름 제어와는 다른 것으로 네트워크의 감당여부가 중요하다.(흐름 제어는 송신자와 수신자의 속도 차이를 해결하기 위한 기법)

 

Causes/ costs of congestion : scenario 1

2개의 송신자와 무한 버퍼를 갖는 하나의 라우터

 

 

 

첫 번째 상황은, 라우터의 버퍼가 무한대인 상황이며 당연히 실제로는 없는 이상적인 경우이다.

 

두 호스트 A, B는 λ(in) 바이트/초의 속도로 라우터에게 제공하고, 그에 대한 서버의 처리량은 λ(out)이 되겠다.

 

이 경우 A, B가 보낼 수 있는 최대 속도로 전송을 해도, 라우터의 버퍼는 무한대이기 때문에 보내는 족족 언젠가는 다 오게 되어있다. 덕분에 재전송도 없을 것이다.

 

연결 성능

 

 

 

첫 번째 시나리오에서의 연결 성능을 나타내는 그림이다.

 

왼쪽 그래프는 연결 전송률의 함수로 연결당 처리량을 그린 것이다.

두 개의 호스트가 동시에 보내므로, 출력 링크의 가능한 출력량 R을 2로 나눈 값이 올바른 전송률이 되며,

전송률이 R/2 이상일 때, 처리량은 단지 R/2가 될 뿐이다. (성능은 그대로라는 의미이다.)

 

오른쪽 그래프는 연결당 지연을 그린 것이다.

라우터의 버퍼가 무한대라고 가정했기 때문에 빠른 속도로 계속 보내면 라우터의 버퍼에 무한대로 쌓이게 되며,

위 그래프처럼 딜레이가 아주 크게 증가하게 된다.

 

Scenario 2

2개의 송신자, 유한 버퍼를 가진 하나의 라우터

 

 

두 번째 시나리오는 라우터의 버퍼가 유한하다는 설정을 가진다. 

 

이 경우 버퍼의 오버플로우가 발생할 수 있으며, 만약 오버플로우 발생 시 재전송이 필요하다.

 

추가로 두 번째 시나리오는 3가지 가정을 갖는다.

 

(a). 호스트가 라우터의 버퍼가 비어 있는지 아닌지를 알고, 버퍼가 비어 있을 때만 패킷을 송신한다.

-> 이 경우 시나리오 1처럼 어떠한 손실도 발생하지 않고 처리량은 λ(in)과 같다.

 

(b). 호스트는 패킷이 손상된 것을 알았을 때만 재전송한다.

 

 

-> 이 경우 라우터에서 버려진 패킷에 대해서만 재전송을 하고, 처리되기 때문에 점차 R/2에 가까워지는 구조이다.

 

(c). 유실을 모르고, 타임아웃을 통해서 알게 된다.

 

 

-> 이 경우 타임아웃에 따른 지연으로 인해 송신자의 불필요한 재전송(duplicate)이 생기면서 처리량이 줄어들게 된다.

타임아웃이 발생하면 중복된 패킷을 다시 보내는데, 이 때 원래 보낸 패킷도 수신측에 도착하기 때문에 수신측에서 중복된 패킷이 버려지게 되고 따라서 수신측에서는 처리량이 감소하게 되는 것이다.

 

* goodput 이란? 시나리오 1처럼 R/2 만큼의 출력이 수신되는 아주 좋은 처리량을 의미한다!

 

 

Scenario 3

4개의 송신자와 유한 버퍼를 가지는 라우터, 그리고 멀티홉 경로

 

 

 

 

가장 현실적인 시나리오이다. 여러 개의 호스트와 멀티홉이 존재하는 경우이며, 4개의 호스트는 겹쳐지는 홉 경로를 통해 패킷을 전송한다. 이때 타임아웃/재전송 방식을 사용한다고 가정한다.

 

만약 A -> C, B->D로 각각 패킷을 전송한다고 했을 때, 서로 같은 멀티홉을 지나가는 순간이 존재하기 때문에

서로의 경로에 영향을 받게 된다. 즉, 너무 많은 패킷을 보내려다가 둘 다 못 보낼 수 있다는 뜻이다.

 

시나리오 3에 대한 해결방안

 

1) 종단 간의 혼잡 제어

  • IP 계층이 네트워크 혼잡에 관해서 종단 시스템에게 어떠한 피드백도 제공하지 않으므로 TCP가 수행해야 한다.
  • 타임아웃, 딜레이가 나타날 때 TCP 세그먼트의 손실은 네트워크 혼잡 발생으로 생각할 수 있다.
  • 추가로 TCP는 그에 따라서 윈도 크기를 줄인다.

2) 네트워크 지원 혼잡 제어

  • 라우터가 송신자에게 직접적인 피드백을 제공한다.
  • ex) ATM ABR, ECN, SNA

 

 

 

3.7. TCP 혼잡 제어

 

앞서 배운 것처럼 TCP는 신뢰성을 중요시하는데, 그 요소들 가운데 혼잡 제어 메커니즘이 있다.

 

특히 아까 말한 것처럼 IP는 아~~ 무것도 지원하지 않기 때문에 특히 TCP는 종단 간의 혼잡 제어를 사용해야 한다.

즉, 송신자가 스스로 혼잡 상황에 맞춰 전송률을 조절해야 한다는 것이다.

 

TCP 혼잡 제어의 기본 원리

AIMD (Additive Increase Multiplicative Decrease)

-> 증가할 때는 점진적으로 늘어나고, 감소할 때는 배로(지수적으로) 줄어든다.

  • additive increase : 손실이 감지될 때까지 매 RTT마다 1 MSS씩 증가한다.
  • multiplicative decrease : 손실 발생 후 절반으로 줄어든다.

-> TCP 혼잡 제어 메커니즘은 추가적인 변수인 혼잡 윈도(cwnd)를 사용하여 트래픽 전송 비율을 제한한다.

 

 

이전 포스팅에서 설명한 rwnd가 수신자 버퍼 공간이라면 송신자에겐 cwnd가 있다. 둘 다 의미는 비슷하다.

 

위 그림처럼, 보냈지만 아직 확인 응답받지 못한 "in-flight"는 이전엔 rwnd보다 크면 안 된다고 했지만

이제 cwnd도 나왔기 때문에 min(cwnd, rwnd) 보다 크면 안된다고 바꾸어 생각해보자

 

TCP 전송률

송신자가 cwnd 바이트 크기의 data를 보냈을 경우 RTT를 기다리면 전송률은 cwnd/RTT 가 된다.

 

 

TCP slow start

아까 위에서 TCP 혼잡 제어는 cwnd가 증가할 때 점진적으로 증가하면서 1 MSS씩 더해진다고 했었다.

하지만 TCP slow start 방식은 시작 후 증가율이 지수적으로 증가하게 된다(손실 발생 전까지)

 

매 RTT마다 두배씩 증가하며 start되는 시점에서만 느리다고 해서 slow start라고 이름 지었다. 

TCP slow start도 초기 전송률은 느리지만, 점점 아주~ 빨라진다!

 

 

TCP 손실 발견 시 대응

대응 방식은 두 가지가 있는데, 각각 TCP Tahoe, TCP RENO라는 방법이다.

 

TCP Tahoe (예전 방식)

  • 손실 발생 시 cwnd는 1부터 다시 시작한다.
  • cwnd는 슬로 스타트 부분에서 지수로 증가하고, 이후 혼잡 회피 단계에서 점진적으로 증가한다.

TCP RENO

  • 3개의 중복 ack을 받은 경우 cwnd를 절반으로 줄인다.
  • 하지만 타임아웃은 1부터 다시 시작한다.

추가) 쓰레쉬(ssthresh)

  • 슬로 스타트 임계치의 약자로 여기서 보통 cwnd/2로 정한다.

 

Fast Recovery

빠른 회복에서 cwnd 값은 잃었던 세그먼트에 대한 매 중복된 ACK를 수신할 때마다 1 MSS씩 증가된다. 

이는 아직 중복된 ACK에 대한 세그먼트를 받지 못했어도, 계속 cwnd를 증가시켜 손실 이후 빠른 회복을 도모한다.

 

요약 : TCP 혼잡 제어

 

 

 

순서

  • 1. 초기에 slow start에서 시작하며 거꾸로 된 V 모양처럼 변수를 초기화해준다.
  • 2. ACK을 계속 받다가, cwnd가 ssthresh 이상으로 증가하는 순간 혼잡 회피 단계로 이동한다.
  • 3. 혼잡 회피 단계에서는 새로운 ACK에 대한 cwnd 증가량이 점진적으로 늘어나게 된다.
  • 4. 만약 중복 ACK을 3개 받았다면 ssthresh와 cwnd가 줄어들며 빠른 회복 단계로 이동한다.

순서는 다양하게 바뀔 수 있으며, 여기서 timeout 상황은 세 군데 모두 동일하다.

 

 

TCP 공평성

TCP는 신뢰적인 프로토콜이므로 호스트 별로 공평한 송신율을 가지고 있어야 한다.

 

왜 TCP가 공정한가?

 

 

위 그림은 두 호스트 간의 전송률에 따라 손실이 발생하면서 대역폭이 동등해지는 과정을 나타낸다.

하지만 그림이 좀 이해하기 어려운데, 의외로 좀만 생각하면 간단하다.

 

2개의 TCP connection이 있다고 가정했을 때

 

R1 + R2 <= R

0 <= R1 <= R

0 <= R2 <= R

 

위 조건을 만족해야하므로 위와 같은 삼각형 영역안에서 throughput을 갖게 된다.

임의의 한 지점에서 loss가 발생했을 때 x축으로 절반, y축으로 절반씩 감소하면서 fairness를 보장해준다. 

 

예를 들어 전송률 R을 갖는 하나의 링크를 공유하는 호스트 A, B가 있고, 각각에 대한 전송률이 C1, C2이고, R의 최대치는 15이다.

 

최초의 전송률은 C1 = 10, C2 = 2라고 하고, 그에 대한 합은 12이다.

아직 괜찮으니 1씩 더한다.

C1 = 11, C2 =3이고, 합은 14이다.

아직 괜찮으니 1씩 더한다.

C1 = 12, C2 = 4이고, 합은 16이다. 패킷 손실이 발생했으니 반으로 감소시킨다. C1 = 6, C2 = 2이다.

 

이런 식으로 점점 나가다 보면 결국엔 C1, C2는 비슷한 수치로 수렴하게 될 것이다. 방금 (10, 2)에서 (6,2)로 변한 것처럼 말이다.

 

 

참고자료

https://seungjuitmemo.tistory.com/89?category=925884 

https://suhwanc.tistory.com/106?category=781986 

https://suhwanc.tistory.com/107?category=781986 

'CS 공부 > 네트워크' 카테고리의 다른 글

Chapter 3 - Transport Layer(1)  (0) 2021.09.26
Chapter2 - Application Layer(2)  (0) 2021.09.21
Chapter2 - Application Layer(1)  (0) 2021.09.21
Chapter 1 - Computer Networks and the Internet  (0) 2021.09.05