TCP Reliable Services
TCP 신뢰성 서비스
- UDP와 달리, TCP에서는 네트워크 상에서 원활하고 안전한 통신을 위해 7가지 서비스를 제공하는데,
신뢰성 서비스는 그 중 하나이다.
- TCP 신뢰성 서비스를 구성하는 메커니즘은 아래와 같다:
- Error Control (에러 제어)
- Flow Control (흐름 제어)
- Congestion Control (혼잡 제어)
- 신뢰성 서비스를 이루는 메커니즘은 아래와 같다:
- EDC (Error Detection Code)
- ACK
- Time-Out
- Retransmission
- Sequence Number
- Window
* 본 포스트는 Transmission Control Protocol (TCP 프로토콜) 의 하위 문서이다. (URL)
Error Control (에러 제어)
- IP는 Connectionless Service를 제공하기 때문에, 패킷(데이터)이 순서대로 도착하리라는 보장이 없다.
- TCP에서는 Error Control을 위해 아래와 같은 메커니즘들을 사용한다:
- Checksum
- ACK
- Time-Out
- Sequence Number
- Buffering
- Retransmission
Fast Retransmission
- TCP의 대부분의 버전에서 사용하는 기법이다.
- ACK에는 여지껏 수신했던 패킷 중 가장 큰 바이트 번호, 수신 윈도우 크기가 저장되어 있다.
- 데이터가 없는, 순수한 ACK 메시지는 Seq #를 소비하지 않고, ACK에 대한 ACK를 송신하지 않는다.
- RTO Timer(재전송 타이머) : Time-Out될 시, 패킷을 재전송한다. 재전송 타이머는 패킷을 전송할 때마다 작동하지 않고, Send Queue의 맨 앞에 패킷이 전달될 때에만 작동한다.
- 클라이언트에서 Send Window의 맨 앞에 위치했던 Segment(101-200)을 서버에 전송한다. (이 때, RTO 타이머가 작동된다.)
- 이후에 Segment(201-300)까지 수신한 서버에서 ACK(301)을 송신한다.
(TCP에서는 ACK의 수를 줄이는 것을 지향하기 때문에, 연속된 두 개의 패킷이 도착하면 하나의 ACK를 전송한다.)
- ACK를 받은 클라이언트에서는 RTO 타이머를 Stop시킨다.
- 이후, 클라이언트가 보낸 두 개의 Segment(301-400, 401-500) 중 Segment(301-400)이 Lost되더라도 클라이언트 측에선 패킷을 계속해서 보낼 수 있다. (이 때도, Send Window의 맨 앞에 있던 Segment(301-400)가 전송되면 RTO 타이머가 다시 동작한다.)
- 서버측에선 ACK로써 "연속적으로" 수신에 성공한 Seq #을 알려야 하기 때문에, 중간에 Lost된 Segment(301-400)에 대한 ACK(301)를 이후의 Segment들을 받을 때마다 그 즉시 클라이언트에게 보낸다.
(즉, 이후에 수신에 성공한 Segment들과 관계없이 ACK는 항상 301번 ACK로 보낸다.)
- Lost된 Segment의 자리는 비워둔 채로, 이후 수신되는 Segment들은 순서에 맞춰서 Receive Buffer에 보관한다.
- Segment(301-400)을 전송한 이후로, ACK(301)을 세 번이나 수신(Third Duplicate)한 클라이언트는 Segment(301-400)에 대한 Lost 사실을 알아차려 Resent한다.
- 즉, RTO 타이머가 만료되지 않았더라도, Third Duplicate되면 ACK에 대한 Segment를 재전송(Fast Retransmit)한다.
- Fast Retransmit은 RTO 타이머를 Restart(Stop시킨 후 다시 동작)시킨다.
- 서버측에선, Lost되었던 Segment가 도착하면 그 즉시, ACK(701)을 전송한다.
- 실제로, 패킷들은 매우 빠른 시간내에 연속적으로 전송되어 3개의 Segment와 ACK가 오고가기 까지 위 그림처럼 오랜 시간 (3배가 넘는 RTT)이 소요되지 않는다.
- 왼쪽 그림에서와 같이 RTT와 많은 차이가 나지 않는 시간동안 Third Duplication이 발생하므로, RTO 타이머에 Time-Out이 발생하지 않는 것이다.
※ 위 그림에서는 3배의 RTT (Round Trip Time)가 이루어지는 동안 RTO 타이머가 만료되지 않아,
실제 환경과 약간 괴리가 있다.
Sender Site에서의 Finite State Machine Model
State: Ready
- Send Window에서 더 송신할 수 있는 여력이 있는 상황을 의미한다.
State: Blocking
- Send Window가 꽉차서 더 이상 보낼 수 없는 상황을 의미한다.
※ Send Window는 3가지 상태로 존재할 수 있다.
1. Sf와 Sn 모두 Window의 맨 앞부분을 가리키는 상태 (Ready 상태)
- 내가 전송한 패킷들에 대한 ACK를 모두 받은 상태이다.
- 당연히, 패킷을 보낼 여력이 있는 상황이다.
2. Sf는 Window의 맨 앞, Sn은 Window의 중간 부분을 가리키는 상태 (Ready 상태)
- 내가 전송한 패킷들에 대한 ACK를 일부만 받은 상태이다.
- 이 또한, 패킷을 보낼 여력이 있는 상황이다.
3. Sf는 Window의 맨 앞, Sn은 Window의 맨 뒤를 가리키는 상태 (Blocking 상태)
- Send Window 크기 만큼 패킷을 전송하고, 아직 아무런 ACK를 받지 못한 상태이다.
- 패킷을 더 보낼 여력이 없는 상황이다.
A chunk of bytes accepted from the process
- Ready 상태에서, 응용 프로세스로부터 Data(Byte)를 수신하면 Segment를 만들며, Seq #은 Sn으로 설정한다.
- 생성한 Segment는 Send Window에 저장된다.
(Segment가 Send Window에 추가된 이후, Sn = Sn + Data Length로 갱신한다.)
- 만약 해당 Segment가 Send Window의 맨 앞에 위치했다면, 재전송 타이머를 동작시킨다.
- 이미 Send Window에 하나 이상의 Segment가 대기중이라면, 이미 타이머가 동작 중인 상황이다.
Window full?
- Send Window가 꽉 찼는지를 검사한다.
- 빈 공간이 있다면, Ready 상태로, 빈 공간이 없다면 Blocking 상태로 접어든다.
- Send Window가 일부 차 있는 상황에서(재전송 타이머가 이미 동작 중), 추가로 Segment들이 추가되어 Send Window가 꽉 찬 경우, Blocking 상태로 접어든다.
- Send Window가 비어있는 상황에서 다량의 Segment(혹은 큰 Segment)가 추가(재전송 타이머가 새로 동작)되어 한꺼번에 Send Window가 꽉 차게 된 경우, Blocking 상태로 접어든다.
An error-free ACK arrived that acknowledges the segment in front of the queue
- Queue의 맨 앞에 위치한 Segment에 대한 정상적인 ACK를 수신한 경우이다.
- Sf를 ACK 번호로 설정한다. (Window의 Left-Wall은 항상 ACK 번호에 맞춘다.)
- Window Size는 ACK로 부터 받은 rwnd로 설정한다.
- 이미 ACK가 된 패킷들을 Queue에서 삭제한다.
- 아직 Queue속에 Segment가 남아있다면(ACK를 수신하지 못한 경우), 타이머를 재가동한다.
- Queue가 비었다면, 타이머를 Stop한다.
※ 첫 번째 Segment에 대한 정상적인 ACK를 수신하고, Ready -> Ready, Blocking -> Ready, Blocking -> Blocking 상태로 전이되는 세 가지 경우가 존재할 수 있다.
1. Ready -> Ready Case
- 이 케이스는 다시 두 가지 경우로 나뉜다.
1) Send Window에 있는 패킷들 중 일부에 대해서만 ACK가 도착하면 일단 재전송 타이머를 Stop 시킨 후, ACK가 도착한 패킷은 폐기하고, ACK가 도착하지 않은 패킷 중 첫 번째 패킷의 바이트 번호를 Sf로 설정한다.(Left Wall을 ACK 번호에 맞춤)
- Window의 크기를 ACK로부터 받은 rwnd로 설정한다.
- 설정을 마친 뒤, 재전송 타이머를 Restart 한다.
2) Send Window에 있는 패킷들 전체에 대한 ACK가 도착하면 일단 재전송 타이머를 Stop 시킨 후, Send Window의 Left Wall을 ACK번호로 맞춘다. (이 경우, Sf와 Sn 모두 ACK번호로 설정된다.(Window가 비었기 때문 = Outstanding Packet이 없기 때문이다.)
- Window의 크기를 ACK로부터 받은 rwnd로 설정한다.
- Window가 비었으므로 타이머를 재가동하지 않는다.
2. Blocking -> Ready
- Window가 꽉 찬 상태(Blocking State)에서 일부의 패킷에 대해서만 ACK가 도착한 경우 일단 재전송 타이머를 Stop 시킨 후, Sf는 ACK 번호로, Sn은 Window에 들어있는 패킷의 꼬리 부분(가장 마지막 Seq #)을 가리키게 된다.
- 이 때, ACK로부터 수신한 rwnd의 값이 남은 패킷들의 길이보다 큰 경우이다. (그래야 Window에 남은 공간이 생기기 때문이다.)
- 즉, Window의 일부가 다시 빈 상태가 되었으므로 Ready 상태로 접어들고, 재전송 타이머를 Restart한다.
3. Blocking -> Blocking
- Window가 꽉 찬 상태(Blocking State)에서 일부의 패킷에 대해서만 ACK가 도착한 경우 일단 재전송 타이머를 Stop 시킨 후, Sf는 ACK 번호로, Sn은 Window에 들어있는 패킷의 꼬리 부분(가장 마지막 Seq #)을 가리키게 된다.
- 위 경우와 달리, ACK로부터 수신한 rwnd의 값이 남은 패킷들의 길이와 일치하는 경우이다. (그래야 Window가 다시 꽉 찬 상태가 되기 때문이다.)
- 즉, 다시 Window가 꽉찬 상태가 되었으므로, 다시금 Blocking 상태로 접어들고, 재전송 타이머는 Restart 한다.
Time-out occured
- Ready 상태에서의 Time-out이나, Blocking 상태에서의 Time-out이나 대처 방법은 동일하다.
- Time-out이 발생하면, Send Window의 맨 앞에 위치한 Segment를 다시 전송하고, 타이머를 Restart한다.
A corrupted ACK arrived
- Ready 상태에서나, Blocking 상태에서의 오류가 있는 ACK에 대한 대처 방법은 폐기하는 것이다.
A duplicate ACK arrived
- Ready 상태에서나, Blocking 상태에서의 중복된 ACK에 대한 대처 방법은 동일하다.
- 중복된 ACK의 개수를 세는 카운터(dupNo)를 하나 증가시킨 후, dupNo가 3인지를 검사한다.
- dupNo = 3이라면 Send Window의 맨 앞에 위치한 Segment를 다시 전송하고, 타이머를 Restart하며, dupNo를 0으로 설정한다.
- dupNo != 3이라면, 아무런 동작도 취하지 않는다.
Receiver Site에서의 Delayed ACK
- ACK는 아무 데이터를 포함하고 있지 않기 때문에, 순수한 Overhead라 볼 수 있다.
(이 때문에, TCP가 ACK의 개수를 줄이는 것을 지향하는 것이다.)
- Receiver는 Segment를 수신함과 동시에 ACK Delaying Timer가 가동되고 있는지를 검사한 후, Stop상태라면 ACK Delaying Timer를 Start한다.
(ACK Delaying Timer의 만료 시간은 보통 50ms 수준이다.)
- 연속된 두 개의 Segment를 수신하면 ACK Delaying Timer를 Stop시키고, ACK를 전송한다.
- 하나의 Segment를 수신한 후, ACK Delaying Timer가 Time-Out된 경우, 하나의 Segment에 대한 ACK를 전송한다.
(Sender측에의 재전송 타이머 Time-out을 방지하기 위함이다.)
- 즉, 1개 혹은 2개의 Segment를 수신하면 ACK를 보낸다.
Receiver Site에서의 Finite State Machine Model
An expected error-free segment arrived
- 오류없는 segment가 도착한 경우이다.
- 수신한 segment를 Buffer에 삽입하고, Rn을 Rn + Data Length로 갱신한다.
- ACK Delaying Timer가 가동중이었다면(방금 수신한 Segment가 두 번째 Segment였다면) Stop시키고, ACK를 전송한다.
- 그렇지 않은 경우, ACK Delaying Timer를 Start한다.
A request for delivery of k-bytes of data from process came
- L5의 응용 프로세스로부터 k-bytes 만큼의 데이터를 요청받은 경우이다.
- Buffer의 앞에서부터 k-bytes 만큼의 데이터를 보내고, Window의 크기를 k-bytes만큼 증가시킨다.
An error-free duplicate segment or an error-free segment with sequence number outside window arrived
- 오류는 없으나 중복된 패킷 혹은 오류는 없으나 Window 밖을 벗어난 패킷이 도착한 경우이다.
- 우선적으로, 중복된 패킷이 도착하면 폐기한다.
- 폐기한 후, ACK를 전송한다. (ACK 번호 Rn, 기존의 rwnd 값)
A corrupted segment arrived
- Bit error가 발생한 패킷이 도착하면 폐기한다.
An error-free, but out-of order segment arrived
- 오류는 없으나 순서에 맞지 않는 패킷이 도착한 경우이다. (중복의 경우는 여기에 해당되지 않는다.)
- 해당 Segment를 Buffer의 제 위치에 저장하고, 기존에 전송했던 ACK를 다시 보낸다.
ex) 601번 패킷을 기대중인 상황에서, 701을 먼저 받았다면, Buffer 내에 701에 해당되는 위치에 패킷을 저장하고, 여전히 ACK는 601번으로 전송한다.
ACK-delaying timer expired
- ACK-delaying timer가 Time-Out되면, 그 즉시 ACK를 전송한다.
- 일반적인 클라이언트-서버 간 통신 형태이다.
- 여기서, Rule은 ACK를 보내는 규칙을 의미한다.
Rule 1: 보낼 데이터가 있는 경우, 데이터와 더불어 ACK까지 실어서 전송하는 방식이다.
(이를 "Piggybacking한다" 라고 표현한다.)
Rule 2: ACK-delaying time가 Time-out되면 그 즉시 ACK를 전송한다.
Rule 3: ACK-delaying time가 Time-out되기 전에, 연속된 두 패킷이 도착했다면, Timer를 Stop시키고, 즉시 ACK를 전송한다.
- Send Window의 맨 앞에 위치한 데이터가 전송되면, RTO(ReTransmission Timer; 재전송 타이머)가 동작한다.
Rule 4: Server 입장에서, 순서가 맞지 않는 패킷이 먼저 도착하면 그 즉시 기존에 전송했던 ACK(Seq # 701)를 다시 보낸다.
- Client 입장에서, 중복된 ACK를 수신하면, 중복된 ACK를 수신한 횟수를 카운팅한다.
- 중복된 ACK를 수신한 상황에서 RTO가 Time-out되면 Send Window의 맨 앞에 위치했던 패킷(Seq # 701-800)을 재전송하고, RTO를 재가동한다.
Rule 5: 누락되었던 패킷이 도착하면 그 즉시 ACK를 보낸다.
- ACK를 수신하지 못해도, 계속해서 전송할 데이터가 존재하여, 전송을 계속하는 예시이다.
- Send Window의 맨 앞에 있는 데이터(Seq # 501-600)가 전송되면, RTO를 가동한다.
- Server에 연속된 두 패킷이 도착했으므로, ACK(701)을 전송했으나 실패했다.
- 클라이언트는 ACK를 수신하지 못해도, Send Window가 열려있다면 계속해서 패킷을 전송할 수 있다.
- 이후에, Server에 연속된 두 패킷이 도착하여 ACK(901)을 전송하고, 전송에 성공했다면, 클라이언트는 Seq # 501부터, Seq # 900까지 정상적으로 송신되었다 간주한다. (Cumulative ACK)
- 더 이상 전송할 데이터가 없는 상황에서 ACK를 수신하지 못한 경우의 예시이다.
- Send Window의 맨 앞에 있는 데이터(Seq # 501-600)가 전송되면, RTO를 가동한다.
- RTO가 Time-Out되는 동안, ACK를 수신하지 못하면 Send Window의 맨 앞에 위치한 데이터를 재전송한다.
Rule 6: 중복된 패킷(Seq # 501-600)을 수신하면, 그 즉시 ACK를 전송한다.
(두 패킷을 정상적으로 송신했으나, ACK만 못 받은 상황임을 상기하자.)
- ACK가 누락되어 Deadlock이 발생한 경우의 예시이다.
- 수신자의 rwnd = 4KB인 상황에서, 송신자가 4KB의 데이터를 전송하면, 수신자는 ACK를 보내며 rwnd = 0임을 알린다.
- 송신자도 Window 크기를 0으로 조절하여 데이터 송신을 멈춘다.
- Silly Window Syndrom을 방지하기 위해 수신자는 rwnd의 크기가 충분히 확보된 후에 송신자에게 ACK를 보내어 rwnd가 회복되었음을 알린다.(rwnd = 2KB까지 회복)
- 여기서, rwnd = 2KB임을 알리는 ACK가 정상적으로 전달되지 못하면 deadlock이 발생하게 된다.
(송신자는 아직 수신자의 rwnd = 0으로 알고 있고, 수신자는 송신자가 보낼 데이터가 없어서 안 보내는 것으로 착각하는 교착상태를 의미한다.)
Deadlock 예방책
- 이러한 deadlock을 방지하기 위해, 송신자측에서 rwnd = 0인 ACK를 수신하면 특정한 Timer를 동작시켜 rwnd의 Update 사실을 기다린다.
- 이 Timer가 Time-out되면, 수신자에게 Probe Signal을 전송하여, rwnd 크기의 업데이트 여부를 묻는다.
- 이 Probe Signal을 받은 수신자는 rwnd = 2KB에 해당하는 ACK를 재전송하여 deadlock 상태를 벗어난다.
Flow Control (흐름 제어)
- Send Window와 Receive Window 개념을 이용한 신뢰성 서비스이다.
- TCP/IP Protocol Suite에서 Sender와 Receiver 사이의 데이터 흐름을 나타낸 그림이다.
- Sender내부에서 일어나는 Push Service는 L5가 L4에게 일방적으로 데이터를 보내기 때문에 Flow Control이 필요하다.
(단, 이 경우는 Sender 내부에서 일어나기 때문에 해결하기 쉬운 형태이다.)
- Sender의 L4에서 Push Service를 통해 Receiver의 L4로 데이터를 전송할 때 Flow Control이 필요하다.
(이 경우, 다른 머신 간에서 이루어지기 때문에 Window 개념을 이용하여 해결한다.)
※ Pull Service의 경우, 데이터를 필요한 만큼만 가져가는 형태이기 때문에 Flow Problem이 발생하지 않는다.
- Send Window, Receive Window를 활용하여 Flow Control을 수행하는 예시이다.
- 클라이언트-서버 환경이므로 Connection Establishment시에 SYN, SYN+ACK, ACK를 주고 받는다.
- Bidirectional Communication이 가능하지만 본 포스트에서는 클라이언트가 서버에게 메시지를 보내는 경우만 살펴본다.
- 클라이언트가 서버에게 보내는 SYN에는 데이터가 포함되지 않지만, Seq #을 하나 차지하므로, 이후에 Data Tranfer 과정에서는 Seq # 101부터 사용된다. (101은 서버 Window의 시작번호로 활용된다.)
- 서버는 클라이언트에게 SYN+ACK를 전송한다. 여기에는 서버 자신이 앞으로 사용할 Seq # 1000과 SYN에 대한 ACK, rwnd(초기 Buffer 크기)를 전송한다.
- 클라이언트는 서버로부터 수신한 SYN+ACK를 통해 Send Window를 구축한다.
(이후로는 클라이언트가 서버에게 데이터를 전송하는 경우만 다룬다.)
4번 메시지
- 클라이언트가 Seq # 101부터 200Bytes의 데이터를 서버에게 전송했다.
- \(S_{f}\)는 Seq # 101을 가리키며, \(S_{n}\)은 Seq # 301을 가리키게 된다.
5번 메시지
- 데이터를 수신한 서버는 301 ACK를 클라이언트에게 전송하며, 동시에 rwnd가 600임을 알린다.(200Bytes의 데이터를 수신했으므로 200만큼 감소된다.)
- 5번 ACK에 의해 Send Window또한 Receive Window와 같이, 크기가 600으로 감소된다.
(전반적으로, Send Window와 Receive Window는 서로 크기를 같게 한다.)
6번 메시지
- Seq # 301부터 시작하는 300Bytes의 데이터를 서버에 전송한다.
- \(S_{f}\)는 301을, \(S_{n}\)은 601을 가리키게 되며 Window의 크기는 변함없이 600Bytes이다.
- 서버는 6번 메시지를 받은 후, 응용 프로세스에서 100Bytes만큼의 데이터를 Consume하여 100Bytes만큼 Right Wall이 오른쪽으로 이동하여 1,001을 가리키게 된다.
7번 메시지
- 빈 공간의 첫 번째 Byte Number(601)을 ACK Number로 활용하고, rwnd는 400임을 클라이언트에게 알린다.
- 7번 ACK를 수신한 클라이언트는 600번 까지의 데이터를 삭제하고, Left Wall을 601로 설정하고, Window Size는 400으로 설정하여 서버의 Window와 일치시킨다.
8번 메시지
- 서버의 응용 프로세스가 200Bytes만큼의 데이터를 읽어가, rwnd 값이 200만큼 증가하여 rwnd가 600임을 ACK를 통해 클라이언트에게 알린다. (Seq #에는 변화가 없음에 유의하자.)
※ Window는 Buffer보다 작을 수 있으며, 응용 프로세스는 Winodw를 넘어서 Buffer의 끝에 위치한 데이터까지 사용할 수 있다.
- Buffer의 크기는 변하지 않으며, 변하는 것은 Window이다.
(Buffer: 저장 공간, Window: 저장 가능 공간)
Silly Window Syndrome
- Flow Control 수행 중, 발생하는 부작용을 의미한다.
- Sender/Receiver의 응용 프로세스가 데이터 생성/처리를 느리게 수행해서 발생하는 현상이다.
1. Sender측에서 발생하는 Syndrome
- Sender의 응용 프로세스가 매우 느리게 데이터를 생성하는 경우에 발생한다.
- 가급적 1 Byte 데이터를 전송하지 못하게 제한하며, 되도록 큰 Block Data를 전송하록 권장한다.
- Segment의 경우, 20Bytes의 TCP 헤더와 20Bytes의 가상 IP 헤더가 기본적으로 붙는다. 즉, 1Byte의 데이터를 전송하기 위해 40Byte의 헤더를 붙이는 것을 방지하는 정책이다.
- Nagle Algorithm*을 이용하여 큰 데이터를 전송하도록 한다.
* Nagle Algorithm (네이글 알고리즘)
- 첫 Byte는 그대로 전송하되, 이후 ACK 수신받거나, 최대 크기의 Segment를 생성하면 전송한다.
2. Receiver측에서 발생하는 Syndrome
- Receiver의 응용 프로세스가 매우 느리게 데이터를 처리하는 경우에 발생한다.
- Sender는 느린 Receiver로 인해 계속해서 1Byte의 데이터만 간헐적으로 보낼 수 있는 상황에 처한다.
- 이에 대한 해결책으로 Clark Solution과 Delayed ACK가 있다.
Clark Solution
- 충분한 공간이 생기거나 적어도 Buffer가 반 이상 비어 있을 때 까지 Window의 크기를 0으로 유지하는 방법이다.
- 데이터를 빨리 보낼 수 있는 방법은 아니지만, 네트워크에 있는 패킷의 수를 대폭 줄여서 네트워크에 부담을 덜어내는 방법이다.
Delayed ACK
- 데이터를 수신해도 즉각적으로 ACK를 보내지 않고, 충분한 시간이 지난 후에, Window의 여유 공간이 생기면 그 때 ACK를 전송하는 방식이다.
- 단, Time-Out이 발생되지 않는 선에서 ACK를 추후에 전송해야 한다.
Congestion Control (혼잡 제어)
- Flow Problem은 송신자와 수신자 사이의 문제인 반면,
Congestion은 송신자와 수신자 사이의 네트워크에서 발생하는 문제이다.
Congestion Window
- 네트워크가 받을 수 있는 데이터의 양을 Window 개념으로 생각하는 방법이다.
- 네트워크 측의 Window를 Congestion Window라고 한다.
- Congestion Window는 정확히 계산할 수 없으므로, 송신자는 Congestion Window를 추측하여 데이터를 전송한다.
- 즉, 송신자의 Window 크기는 Congestion Window, rwnd의 크기를 넘을 수 없으며, 둘 중 작은값으로 일치시킨다.
(\(swnd = MIN(cwnd, rwnd)\))
- Congestion 또한, Byte Number로 제어된다. (설명의 편의를 위해 하나의 패킷에 하나의 ACK가 전송된다 가정한다.)
- 통신 초기에는, cwnd를 MSS* 1개의 사이즈로 간주하여, 하나의 Segment만 전송한다. (Pessimistic Way; 비관적 방법)
- 하나의 Segment에 대한 ACK를 수신한 후, cwnd를 ACK를 받은 개수만큼 증가시킨다. (즉, 하나의 ACK를 수신했으므로, cwnd를 1만큼 증가시킨다.)
- cwnd=2로 추측하고 있으므로, 2개의 Segment를 보내고, 그에 대한 2개의 ACK를 수신하여 cwnd를 2만큼 증가시킨다.
- 이러한 방식으로 cwnd는 기하급수적으로 증가하여 위험한 상황을 초래할 수 있으므로, 특정한 Threshold(한계점)에 도달하기 전 까지만 이러한 방식을 적용하여 cwnd를 증가시킨다.
- 특정한 Threshold(한계점)에 도달하면, 천천히 증가하도록 방법을 바꾸게 된다.
* MSS: Maximum Segment Size
- Threshold(한계점)에 해당하는 cwnd가 4라고 가정하자.
- 4개의 Segment에 대한 4개의 ACK를 수신하면, cwnd를 8로 증가시키지 않고, 1만큼만 증가시켜 cwnd를 5로 설정한다.
- 즉, Exponential하게 증가하다가 Threshold(한계점)에 도달하면, Additive하게 증가시키는 방식이다.
- Additive하게 증가시키다가 Congestion이 감지되거나 rwnd를 초과하게 되면 증가시키는 것을 멈춘다.
Congestion Policy
- 처음 TCP Connection이 개설되면, Slow Start 방식(Exponential Increase)으로 진행한다.
- cwnd를 증가시키다, ssthresh(Slow Start Threshold)값을 넘어서게 되면 Congestion Avoidance 방식(Additive Increase)으로 변경한다.
- Connection Termination은 꼭 이러한 Increase 과정에서 일어난다는 보장은 없다.
Issues
- TCP에서는 Duplicate ACK 보다 Time-Out을 더욱 심각한 상황으로 간주한다.
(중복된 ACK는 Lost된 패킷 이후의 패킷들은 정상적으로 수신되었음을 의미하지만, Time-Out은 전체 패킷이 모두 수신에 실패했을 가능성도 있기 때문이다.)
1. Time-Out (Worst Congestion)
- ssthresh를 현재 Window 크기의 절반으로 감소시킨다.
- cwnd를 다시 1MSS로 설정한다. (다시 Minimum으로 설정된다.)
- 설정을 마친 뒤, Slow Start를 다시 시작한다. (Exponential Increase 시작)
2. 3-Duplicate ACKs (Worse Congestion)
- ssthresh를 현재 Window 크기의 절반으로 감소시킨다.
- cwnd를 ssthresh로 설정한다.
- 설정을 마친 뒤, Congestion Avoidance부터 다시 시작한다. (Additive Increase 시작)
Reference: TCP/IP Protocol Suite 4th Edition
(Behrouz A. Forouzan 저, McGraw-Hill, 2010)
Reference: Data Communications and Networking 5th Edition
(Behrouz A. Forouzan 저, McGraw-Hill, 2012)