ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [네트워크] 11. TCP
    CS/네트워크 2023. 4. 11. 23:19

    1. TCP

    이제부터 reliable data transfer protocol 중 하나인 TCP에 대해 알아보도록 하겠습니다.

     

    1.1 TCP reliable data transfer

    TCP는 다음과 같은 특징을 가집니다.

    • pipelined segment : 여러 개의 segment를 한번에 전송하고, ACK를 한번에 받습니다.
    • culmulative ACK : 누적 ACK라는 의미로, 매 번 ACK를 보내는 것이 아니라 누적 ACK를 보냅니다.
    • single retransmission timer : 가장 오래된 segment를 기준으로 timer를 한 개만 설정합니다.
    • retransmission은 timeout또는 duplicate ACK 에 따라 발생합니다.

    우선 duplicate ACK를 고려하지 않는 단순한 형태의 TCP에 대해 알아보도록 하겠습니다.

     

    TCP sender events는 다음과 같습니다.

    Data received from app

    • seq num로 세그먼트를 생성합니다.
    • seq num은 세그먼트의 첫 번째 byte의 offset입니다. (1, 2, 3 ... 으로 증가하는 것이 아닌 세그먼트 크기만큼 증가합니다.)
    • 타이머가 실행중이 아니라면 타이머를 실행합니다. (타이머는 가장 오래된 ACK를 받지 않은 세그먼트를 기준으로 합니다.)

    Timeout

    • timeout이 걸리면 세그먼트를 다시 보냅니다. 이후 타이머를 다시 시작합니다.

    ACK received

    • ACK를 받은 것에 대한 버퍼링을 합니다.
    • 아직 ACK를 받지 못한 것이 있다면 timer를 세팅합니다.
    • 모든 세그먼트에 대한 ACK를 받았다면 타이머를 멈춥니다.

     

     

     

    그럼 단순한 TCP 의 FSM을 보도록 하겠습니다. (Sender)

     

     

    초기 상태는 초기 seqnum을 가지고 시작합니다.

     

    1. Application layer에서 데이터를 받게 되면, 초기 seq num으로 세그먼트를 생성합니다.
    2. 세그먼트의 크기만큼 Next seq num을 증가시켜 놓고, IP로(network layer) 세그먼트를 전송한 후 타이머를 시작합니다.
    3. ACK가 도착한다면 base를 ACK만큼 이동시킵니다. ACK는 누적 ACK이기 때문에 한번에 이동하게 됩니다.
    4. y는 다음에 받아야 하는 ACK가 되게 됩니다. 만약 ACK를 덜 받았다면, timer을 재설정하고, 모든 ACK를 받았다면 타이머를 종료합니다.
    5. ACK를 받지 못하고 timeout이 걸렸다면, 가장 오래된 unACKed 세그먼트를 다시 보냅니다. 보내면서 타이머도 재설정합니다.

     

     

    이제 Host A와 B가 TCP 통신을 하는 예제를 보도록 하겠습니다.

     

    만약 세그먼트를 보내고, ACK가 유실된다면, timeout에 의해 세그먼트를 다시 보내게 됩니다.

    이 때, Host B는 100번 세그먼트를 보내달라는 의미로 ACK 100을 중복되게 보내게 됩니다.

     

    두 번째 상황으로, 세그먼트를 2 개를 보냈는데, ACK가 늦게 도착해서 timeout이 걸려버린 상황입니다.

    HostA는 세그먼트 92를 다시 보내게 되는데, HostB는 원하는 세그먼트 120이 아니기 때문에, 120을 보내달라는 의미로 ACK 120을 보냅니다. (ACK = Ask)

     

     

     

     

     

     

     

     

    이제 새로운 상황으로, 세그먼트 92와 100을 보냈는데, ACK가 120만 도달한 상황입니다.

    HostA는 ACK120을 받았을 때, 100까지 잘 전달된 것을 알 수 있기 때문에, timeout을 시키지 않고 타이머를 종료시킵니다.

    이렇게 누적 ACK를 사용한다면 ACK가 중간에 유실되더라도 문제가 발생하지 않습니다.

     

    이번엔 receiver의 입장에서 발생한 이벤트에 대해 TCP 방식의 처리를 살펴보도록 하겠습니다.

     

    이벤트 액션
    순차적으로 세그먼트가 도착할 때 Delay ACK를 사용해서 다음 세그먼트를 기다리고, 세그먼트가 오지 않는다면 누적 ACK를 보냅니다.
    세그먼트가 도달했는데 이미 delayed ACK인 경우 두 개에 대한 누적 ACK을 보냅니다.
    만약 중간에 Gap이 생겨서 세그먼트를 받았을 때 일단 버퍼에 저장해두고, 못 받은 ACK를 다시 달라고 중복 ACK를 보냅니다.
    세그먼트가 추가로 와서 Gap을 채웠을 때 Gap이 채워진 것 중 가장 높은 누적 ACK을 보냅니다.

     

    1.2 TCP fast retransmit

    지금까지는 duplicate ACK에 대해서는 고려하지 않은 TCP를 보았습니다.

    이제 duplicate ACK를 보낼 때, 어떻게 처리하면 좋을지 알아봅시다.

    이를 해결할 방법인 fast retransmit에 대해서 알아봅시다.

     

    세그먼트를 보낼 때, Gap이 생겨서 중간에 빠진 세그먼트가 있을 때, receiver는 duplicate ACK를 보내게 됩니다.

    이를 sender가 3개 를 받게 되면, timeout까지 기다리지 않고 Duplicate ACK에 해당하는 세그먼트를 다시 보내줍니다.

    • 참고로 duplicate ACK가 3개로, 실제로 receiver는 4개의 ACK를 보내게 됩니다.

     

     

     

     

    위 상황은 fast retransmit에 대한 내용입니다. duplicate ACK를 3개째 받게 되는 즉시, timeout을 기다리지 않고 해당 ACK에 대한 세그먼트를 다시 보내주고 있습니다.

     

    그럼 세그먼트를 보낸 이후는 어떻게 될까요?

    Host B는 세그먼트를 잘 받은 후, ACK를 보낼 것입니다.

    그런데 얼마를 보내야 할까요?

     

    그림에는 나오지 않았지만, 세그먼트를 5개 보냈는데, 세그먼트 5개까지 seq num 합이 180이라고 했을 때(각각 20byte),

    Host B가 보내는 ACK는 180이 될 것입니다.

     

     

     

     

    1.3 TCP round trip time, timeout

    지금까지 해서 TCP가 ACK를 받는 방식과 처리하는 방식에 대해 알아보았습니다.

    ACK를 retransmit하는 것 까지 알아보았는데요, 이 fast retransmit은 timeout과 큰 연관이 있다고 할 수 있습니다.

    timeout을 어떻게 설정하는 것이 좋을지에 대해 알아봅시다.

     

    timeout이 너무 짧다면, timeout으로 생기는 retransmission이 너무 많을 것입니다.

    반대로 너무 길다면, 세그먼트 유실에 대응하는 것이 너무 느릴 것입니다.

     

    SampleRTT

    하나의 기준으로 SampleRTT가 있습니다. 실제로 세그먼트를 보내고 ACK를 받을 때 까지 걸리는 시간을 의미하는데요,

    이 SampleRTT는 자주 바뀌고, 예측하기 어렵기 때문에, 이를 원만하게 하는(smoother) 방식이 존재합니다.

     

    여기서 보이는 sampleRTT를 이용해, EstimatedRTT를 구하는 것이 목표입니다.

    EstimatedRTT는 다음과 같이 구할 수 있습니다.

     

    EstimatedRTT = (1 - a) * EstimatedRTT + a * SampleRTT

     

    여기서 가중치 a는 0.125 입니다.

    SampleRTT가 변동 폭이 크기 때문에, 가중치를 적게 곱하는 것 입니다.

     

    하지만 EstimatedRTT 만으로는 위험할 수 있습니다.

    당장 그래프에서도 보이지만, sampleRTT가 훨씬 높아지는 부분들이 존재합니다.

    이런 위험을 커버하고, 편차를 어느정도 허용하기 위해, timeout interval을 사용합니다.

     

    Timeout Interval

    timeout interval은 EstimatedRTT에 safety margin을 더한 값입니다.

    다음과 같이 구할 수 있습니다.

    TimeoutInterval = EstimatedRTT + 4 * DevRTT

    여기서  DevRTT는, 편차 RTT를 의미하며, safety margin에 해당합니다.

     

    DevRTT를 구하는 방법은 다음과 같습니다.

     

    DevRTT = (1 - b) * DevRTT + b * abs(SampleRTT - EstimatedRTT)

    보통 b의 값으로 0.25를 활용합니다.

     

     

    그럼 EstimatedRTT와 DevRTT의 초기값은 어떻게 될까요?

    EstimatedRTT의 경우 initialSampleRTT를 그대로 사용하고,

    DevRTT의 경우 initialSampleRTT의 절반을 사용합니다.

     

    실제 예시를 들면 아래와 같습니다.

     

     

    처음엔 Timeout이 높게 잡혔지만, 갈수록 점점 안정화 되어 가는 것을 볼 수 있습니다.

     

    본 글은 Computer networking : a top-down approach 라는 책을 통해 작성되었습니다.

    댓글

Designed by Tistory.