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
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까지 가능하다.
sequence number : data부분에 들어가는 첫번째 byte에 들어가는 seq numb. byte당 seq numb이 부여된다.
TCP에서 ACK에 대한 Sequence number는 내가 0번부터 99번의 seq numb의 데이터를 잘 받았을 경우 100번의 seq numb에 대한 ACK를 전달한다. 이 의미는 100번 데이터가 날라오기를 기다리고 있다는 의미. 누적 ACK 사용
예를 들어 다음과 같이 생긴 sender의 sliding window가 있다고 가정하자.
노란색 패킷에 해당하는 것들은 sender가 보냈지만 ACK를 받지 않아서 아직 sliding되지 않은 패킷들(데이터가 receiver에게 가고있거나, receiver입장에서 ACK를 보냈지만 Sender에게 도착을 하지 않은 상태)이란 의미고, 파란색 패킷은 아직 전송하지 않은 패킷들이라는 의미이다.
이때 ACK를 받았다는 의미인 녹색의 마지막 패킷(이 seq numb을 56이라고 가정하자.)에서는 ACK에 대한 정보 segment 에서 seq number는 56의 다음 패킷 numb인 57을 전달할 것이다.
순서가 바뀌어서 도착한 segment는 TCP 표준 Spec에서는 명시적으로 다루지 않는 경우가 있지만 일반적인 TCP 구현에서는 보통 이런 상황을 처리하도록 구현된다. 다시말해 대부분의 TCP 스택은 도착한 세그먼트를 버리지 않고 일단 받아들여서 순서가 맞지 않는 세그먼트를 버퍼에 저장한 후, 모든 세그먼트가 도착하면 올바른 순서로 재조립된다.
그림에 나와있지 않은 부분이지만 Host B로 부터 seq가 78인 data를 잘 받았으므로 Host A가 ACK 79를 보냈으며, Host A는 Host B에게 Seq numb이 42인 데이터를 보낸 상황이다. 따라서 Host B는 Seq numb이 42인 데이터를 잘 받았다는 의미에서 43의 데이터가 담긴 ACK를 보내고, 또한 데이터로는 79번의 데이터를 기대하고 있다고 했으므로 79번의 데이터를 전달한다.
Timeout
timeout은 어떻게 설정하는 것이 좋을까?
RTT보다는 크면서 : 그렇지 않으면 premature timeout을 발생시켜 불필요한 재전송을 만들면 안된다.
너무 크지는 않아야한다. : 유실된지 한참 후에 전송되면 성능이 떨어진다.
그렇다면 RTT는 어떻게 측정하는가 ?
ACK 가 돌아올때까지의 시간을 측정해서 동적으로 반영한다.
이떄 재전송인 경우 RTT를 측정해서는 안된다 : 이유는 응답의 기간이 아까 보낸 데이터에 대한 ACK인지 마지막에 보낸 데이터에 대한 ACK인지 모르기때문.
Exponential Weighted Moving Average(EWMA)
RTT의 경우 인터넷 상황에 따라서 굉장히 가변적이기때문에 과거에 측정된 데이터와 지금 측정한 데이터의 누적한 값을 반영해야한다.
보통 a는 0.125값을 가진다.
그럼 다시 Timeout으로 돌아와서
Timeout은 premature timeout이 발생하지 않도록 Estimated RTT에 safety margin값을 더한다.
safety margin값으로는 4*DevRTT를 쓰는데, DevRTT값은 기존의 편차(DevRTT)에 누적된 RTT값과 지금 측정한 RTT값의 차이를 통해 다음과 같이 구할 수 있다.
보통 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도 관찰해보자
예상한 시퀀스 번호의 세그먼트가 도착한 경우
- ACK를 delay시킨다. delayed ACK를 사용하니 다음 segment가 올때까지 500ms 가량 기다리고 다음 segment가 오지 않으면 delayed ACK를 보낸다.
예상한 시퀀스 번호의 세그먼트가 도착했지만 이전에 ACK되지 않은 세그먼트가 있는 경우
- delayed된 ACK에 해당하는 in-order segment에게 모두 ACK로 답해줄 수 있는 누적 ACK를 하나만 전송한다.
예상한 시퀀스 번호보다 높은 숫자의 segment가 도착했을때
- 즉각적으로 seq numb으로는 다음 예상되는 이전의 seq numb을 알려주면서 중복 ACK를 보낸다.
부분적으로나 완전히 gap을 채워주는 segment가 도착했을때
- ACK를 즉각적으로 보낸다. segment start를 gap의 시작점에서 가장 낮은 번호로 보낸다.
1. 세그먼트가 gap의 최솟값에서 시작한다고 하면 즉시 ACK를 보낸다.
2. 만약 gap의 최솟값에서 시작하지않으면서 채워주는 segment라면 똑같이 이전에 보내던 ACK seq numb을 보낸다.
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의 빠른 재전송
triple duplicate ACKs
이때까지는 TCP에서 재전송을 하기 위해서라면 Timeout이 발생하는 조건 하나밖에 없었다.
하지만 성능 향상을 위해 timeout이 발생하기 전에도 재전송을 시킬 필요가 있었다. 따라서 중복된 ACK가 3번이상 올 경우 sender입장에서 재전송을 하는 규칙으로 변경하였다. 이때 중복된 ACK 가 3번째 이므로, 똑같은 ACK가 4번째꺼가 왔을때 재전송을 하는 매커니즘이다.
이렇게 빠르게 재전송을 한다면 receiver도 신속하게 sliding하여 빈 버퍼를 만들수 있다는 점에서 성능이 향상된다.
'CS > 컴퓨터 네트워크' 카테고리의 다른 글
[Network Layer 03] Control Plane (1) | 2024.05.28 |
---|---|
[ Network Layer 02] Data Plane (0) | 2024.05.25 |
[ Network Layer 01] Data Plane (1) | 2024.05.20 |
[Tranport Layer 03] TCP의 연결 설정 (0) | 2024.05.03 |
[Transport Layer 01] Pipelining, Go-Back-N, Selective repeat (0) | 2024.05.01 |
댓글