[Transport Layer 02] TCP

    TCP의 특징

    TCP는 하나의 sender당 하나의 receiver가 소통하는 프로토콜이다. 

    또한 checksum을 통해 reliable을 보장하나, 이는 보안을 위한 목적이라기 보다는 정말 약한 확인정도에 불과하다. 

    TCP는 누적 ACK를 사용해 정확히 받은 가장 마지막 seq numb만 전송하고, stop and wait 기법이 아닌 파이프라인 기법을 사용한다. 

    또한 연결 설정을 진행하며 data가 buffer의 size를 넘치지 않도록 flow control과 congestion control 을 사용한다. 

    또한 양방향으로 data전송이 가능한 full duplex data이다. 

     

     

    TCP segment structure

    sequence number : data부분에 들어가는 첫번째 byte에 들어가는 seq numb. byte당 seq numb이 부여된다. 

    Host B로 부터 seq가 78인 data를 잘 받았으므로 Host A가 ACK 79, Seq numb이 42인 데이터를 보낸 상황이다. 

     

     

    ACK number : 다음 예상되는 byte의 sequence number. 99번까지 잘 받았으면 100을 보낸다. 누적 ACK

    A : 이 플래그가 설정되어 있으면, 세그먼트의 Acknowledge Number 필드가 유효하고, 이 번호가 가리키는 데이터까지 수신되었음을 의미. 

    P : P가 1로 setting되어있으면 data를 application으로 바로 push 해라. 

    R : Reset 강제종료. a와 b가 통신하는 도중 b가 어느 순간 응답을 하지 않으면 a가 b를 강제종료시킨다. 

    S : Synchronize 동기화. 최초로 연결하는 과정에서 S가 1이면 연결하겠다는 의미. 이때 initial seq numb이 seq numb에 들어간다. 

    F : Finish a와 b의 정상적인 종료

    receive window : 추가적으로 받아들일 수 있는 버퍼의 양

    options : 옵션이 없는 경우 header는 5줄이다. => 4byte * 5 = 20byte, option의 최대는 40byte이므로 최대 header의 양은 60byte. 

    length : length는 4byte단위로 length값으로 5가 들어있으면 TCP header가 20byte라는 의미이다. length는 따라서 최대 15까지 가능하다. 

     

    Timeout

    timeout은 어떻게 설정하는 것이 좋을까? 

    RTT보다는 크면서 : premature timeout을 발생시켜 불필요한 재전송을 만들면 안된다. 

    너무 크지는 않아야한다.  : 유실된지 한참 후에 전송되면 안된다. 

     

    그렇다면 RTT는 어떻게 측정하는가 ?

    ACK 가 돌아올때까지의 시간을 측정한다. 

    이떄 재전송인 경우 RTT를 측정해서는 안된다 : 응답의 기간이 아까 보낸 데이터에 대한 ACK인지 마지막에 보낸 데이터에 대한 ACK인지 모르기때문. 

     

    RTT의 경우 인터넷 상황에 따라서 굉장히 가변적이기때문에 과거에 측정된 데이터와 지금 측정한 데이터의 누적한 값을 반영해야한다.

    보통 a는 0.125값을 가진다. 

     

    그럼 다시 Timeout으로 돌아와서 

    Timeout은 premature timeout이 발생하지 않도록 Estimated RTT에 safety margin값을 더한다. 

    safety margin값으로는 4*DevRTT를 쓰는데, DevRTT값은 다음과 같이 구할 수 있다. 

    보통 b값은 0.25값을 가진다. 

     

    TCP Sender측에서 발생할 수 있는 Event

    1. application으로부터 data를 받는다. 

    - application이 요청한 데이터를 보내준다. receiver buffer의 빈공간 크기만큼을 잘라서 보내줄 수 있다. 

    - 타이머는 내가 보내놓고 ACK를 받지 않은 segment의 타이머를 기준으로 체크한다. 

    2. timeout된다.

    - 타임아웃을 야기한 segment를 재전송한 후 타이머를 재시작한다. 

    3. ACK를 받는다. 

    - 기존에 ACK를 받지 않았던 segment의 ACK가 도착한다면 window를 slide시킨다. 

     

    이 Event들을 따라 sender의 상태도를 그려보면 다음과 같다. 

     

     

    아무것도 일어나지 않는다면

    - NextSeqNum에 초기 SeqNum이 들어갈 것이고 

    - SendBase에는 초기 SeqNum이 들어갈 것이다. 

     

    Transport Layer의 윗 계층인 application layer로부터 데이터를 받은 상황이라면

    - 보낼 데이터의 segment 단위로 만들고 seq를 부여한다. 

    - Network layer(IP)로 segment를 전달한다.

    - NextSeqNum = NextSeqNum + length(data) 로 업데이트한다. 

    - 만약 타이머가 진행중이 아니라면 타이머를 시작한다. 

     

    timeout이 발생한 경우 

    - 전송을 했지만 아직 ACK를 받지 못한 가장 작은 seqnum에 해당하는 segment를 재전송한다. 

    - 타이머를 시작한다. 

     

    ACK field에 y값을 받으면서 ACK를 받은 경우

    - y값이 SendBase보다 큰 경우

    : SendBase를 y로 업데이트시킨다. (이때 y는 마지막으로 누적된 segment의 seq numb + 1)

    : 아직 못받은 ACK가 있다면 타이머를 시작한다. 아니면 타이머를 중지시킨다. 

     

     

    Receiver의 상태와 event도 관찰해보자

    예상한 seq numb의 segment로 들어올때

    - ACK를 delay시킨다. 누적 ACK를 사용하니 다음 segment가 올때까지 500ms 가량 기다리고 다음 segment가 오지 않으면 누적 ACK를 보낸다. 

     

    예상한 seq numb의 segment로 들어오는데  pending중인 ACK가 안된 segment가 있다. 

    - in-order segment 각각에 대해 ACK를 전송한다. 

     

    예상한 seq numb보다 높은 숫자의 순서에 어긋한 segment가 도착했을때

    - 즉각적으로 중복된 ACK를 보낸다. 그러나 seq numb으로는 다음 예상되는 이전의 seq numb을 알려준다. 

    부분적으로나 완전히 gap을 채워주는 segment가 도착했을때

    - ACK를 즉각적으로 보낸다. segment start를 gap의 시작점에서 가장 낮은 번호로 보낸다.  

     

     

    TCP 재전송 시나리오

    3가지 상황이 있을 수 있다. 

    ACK 유실

    Host A가 Host B에게 92번 seq numb부터 99번 seq numb까지의 데이터를 보냈을때 Host B는 ACK 100을 보냈지만 유실된 상황이다.  

    Host A는 timeout되어 92번 seq numb부터 99번 seq numb까지의 데이터를 재전송하지만 Host B의 Application layer는 이미 앞선 상황에서 제대로 전달받아 중복되어 올려보내지는 않는다. 

     

    Premature timeout

    Host A가 Host B에게 92번 seq numb부터 99번 seq numb까지의 데이터를 보낸 잠시후 100번부터 119번까지의 seq numb의 데이터를 또 다시 보낸 상황이다. 

    Receiver는 92번 seq numb부터 99번 seq numb까지의 데이터를 잘 전송받고 ACK를 보낸후 window 를 slide 하고 100번부터 119번까지의 seq numb의 데이터도 전송받았을때도 마찬가지로 ACK를 전달한 다음 window를 slide 하였다. 하지만 Host A에서 timeout을 너무 짧게 설정하여 timeout이 난 상황에 Host A는 92번 seq numb부터 99번 seq numb까지의 데이터를 재전송하였다. 하지만 그 이후 100 ACK와 120 ACK를 받아서 이후에 보낸 92번 seq numb부터 99번 seq numb까지의 데이터는 Receiver가 무시한다 하지만 이때에도 120 ACK를 전송한다.(전송받은 것은 92~99 데이터이지만 누적되어 정상적인 ACK의 마지막 번호 + 1는 120이기 때문이다. )

     

    ACK가 유실된 상황에서 누적 ACK덕분에 커버를 쳐주는 상황

    Host A가 Host B에게 92번 seq numb부터 99번 seq numb까지의 데이터를 보낸 잠시후 100번부터 119번까지의 seq numb의 데이터를 또 다시 보낸 상황이다. ACK 100이 sender에게 전송되는 도중에 유실되었는데 ACK 120은 정상적으로 잘 도착하였다. ACK 120이라는 말은 즉, seq numb이 119인 데이터까지 빠짐없이 잘 받았다는 의미를 담고있기때문에 이를 전달받은 sender는 그냥 120까지 window를 slide 한다. 

     

    TCP의 빠른 재전송

    이때까지는 TCP에서 재전송을 하기 위해서라면 Timeout이 발생하는 조건 하나밖에 없었다. 

    하지만 성능 향상을 위해 timeout이 발생하기 전에도 재전송을 시킬 필요가 있었다. 따라서 중복된 ACK가 3번이상 올 경우 sender입장에서 재전송을 하는 규칙으로 변경하였다. 이때 중복된 ACK 가 3번째 이므로, 똑같은 ACK가 4번째꺼가 왔을때 재전송을 하는 매커니즘이다. 

    이렇게 빠르게 재전송을 한다면 receiver도 신속하게 sliding하여 빈 버퍼를 만들수 있다는 점에서 성능이 향상된다. 

     

     

    댓글