CS/Computer network

Transmission Control Protocol (TCP) (6)

ys_cs17 2022. 4. 27. 19:52
반응형

WiFi Channels

데이터를 보낼 때는 특정 대역폭을 사용해야 한다. 이 대역폭을 bandwith라고 하고, 만약 channel 1을 통해 데이터를 보내려고 하면, 위 위 그림과 같이 2.4 ~ 2.422 GHz까지의 주파수 영역이 필요하다. 각 채널끼리 간섭을 주지 않으려고 대역폭마다 간격이 존재한다. 하지만 초기 와이파이를 설계했을 당시 채널 간 대역폭을 겹치게 만들었다. 이렇게 겹치는 대역폭 때문에 데이터가 깨지게 되었다.

결과론적으로 1번, 6번 등으로 서로 중첩되게 하면 안된다. 따라서 한 공간에서 대역폭 중첩이 일어나지 않게 하는 경우의 수는 총 3개이다.

1 - 6 - 11 또는 2 -7 - 12, 3 - 8 - 13,...

 

 

TCP timers

TCP에 있는 timers에 대해 살펴보자.

 

(1) Retransmission timer

: Time-out 발생하는 것을 detect 하는 역할. 보통 3-duplicated ACK으로도 탐색을 할 수 있지만, Time-out으로도 packet loss에 대해 탐색이 가능하다. Time-out을 만나면 slow start로 바뀐다.

 

RTO를 정하는 방법은 다음 수식과 같다.

$$\text{RTO} = \text {RTTs} + 4 \times \text{RTTd}$$

여기서 RTTs는 평균, RTTd는 편차라고 이해하면 된다. RTT는 측정을 할 때마다 계속 변화한다. 혼잡 여부에 따라 자주 변화하게 되고, 클 때는 2배까지 차이가 나곤 한다. RTT에서 평균을 구하는 방법은 기존 평균을 구하는 방법과는 차이가 있다.

 

RTTs의 수식은 다음과 같다.

$$\text{RTTs} = (1 - \alpha)\text{RTTs} + \alpha \text{RTTm}$$

이런식으로 가중치를 두면서 평균을 구하는 것을 EWMA라고 부른다. 여기서 RTTm은 새로 측정한 값이고, RTTs는 이전 값이다.

처음 측정을 시작하면 첫 값을 RTTs라고 두고 사용한다. $\alpha$ 값은 $\frac{1}{8}$로 두고 사용한다. 이 값은 실험을 통해서 얻어진 최적의 값이다.

 

RTTd의 수식은 다음과 같다.

$$\text{RTTd} = (1 - \beta ) \text{RTTd} + \beta \mid \text{RTTs} - \text{RTTm} \mid$$

편차에 대해서도 가중치를 적용한다. $\beta$ 값은 $\frac{1}{4}$이다.

수식에서 2번째 term을 보면 RTTs와 RTTm의 distance를 구한다.

만약 첫 번째 측정인 경우 $\text{RTTd} = \frac{\text{RTTm}}{2}$ 로 설정한다.

 

Retransmission timer example

 

만약 client 측에서 SYN으로 연결 요청을 하였는데, 중간에 packet loss 상황이 된다면 time-out으로 detect 할 수 있다. 이 경우에는 server로부터 ACK을 받지 못하는 상황이기 때문에 (server는 SYN도 온 것을 알지 못한다.) 3-duplicated ACK은 사용할 수 없다.

그리고 time-out 후 다시 SYN을 보낸다.

이 경우에 사용하는 RTO 값은 6이다. 이는 시스템의 기본 값이다.

SYN을 보낸 후 부터 RTO timer를 켠다.

위 그림에서는 SYN+ACK이 오는데 1.5s 가 걸렸다. 이때 RTTm은 1.5이고, RTTs도 1.5이다. 그리고 RTTd는 절반인 0.75가 된다.

따라서 RTO를 구하게 되면 $\text{RTO}= 1.5 + 4 \times 0.75 = 4.5$ 가 된다.

 

그러고 나서 2번째 Data socket을 보내준다. 이때 고려해야 할 점은 2~3개를 연달아 보내도 측정은 ACK이 오기 전까지 1개만 한다.

ACK이 2.5s가 되었으면 수식은 다음과 같이 정의된다.

$$\text{RTTm} = 2.5 \\
\text{RTTs} = \frac{7}{8} \times 1.5 + (\frac{1}{8}) \times 2.5 = 1.625 \\
\text{RTTd} = \frac{3}{4} \times 0.75  + (\frac{1}{4})\ \times \mid 1.625 - 2.5 \mid = 0.78 \\
\text{RTO} = 1.625 + 4 \times 0.78 = 4.74$$

 

RTTs와 RTTd를 구해 최종적인 RTO를 구할 수 있다. 

 

Karn's Algorithm

 

Packet을 재전송하는 상황에서는 약간 복잡해진다.

(a) 상황을 살펴보자. packet을 보냈지만 ACK이 오지 않아 Time-out이 되어 재전송을 했다. 그리고 이것에 대한 ACK을 받은 상황이다. 이때 우리는 재전송한 시간과 ACK이 온 시간에 대한 시간을 측정하고, RTO를 구하면 된다. (SampleRTT 아님)

(b) 상왕은 time-out이 발생해서 재전송을 하는데, ACK이 들어온 상황이다. 이는 현재 혼잡해서 ACK이 늦게 들어온 상황이다. 하지만 재전송한 데이터에 대한 ACK이 없어졌다고 가정하자. (b)에서 재전송 보낸 시간과 ACK이 들어온 것이 Sample RTT가 된다. 하지만 이 상황에서 sender는 어떤 packet에 대한 ACK인지 구분하기 힘들어진다.

이를 구별할 수 없어서 Karn algorithm이 고안되었다. 이는 재전송할 때는 해당 측정값을 RTO 계산하는데 쓰지 않는 것이다. 재전송에 대한 time-out은 보긴 하지만 이를 RTO에 측정하지 않는다. 재전송 packet에 대한 RTT 값을 업데이트하지 말고, RTTs, RTTd의 값도 구하지 않는다.

정상적인 packet에 대해서만 restart를 해준다.

 

다음 상황은 packet을 보냈는데 없어진 상황이다. sender는 time-out을 통해 packet loss를 detect 한 상황이다. 이때 재전송할 때는 time-out 시간을 2배 해서 보낸다. 즉 RTO를 2배 해서 보낸다. 이를 exponentail backoff라고 한다.

여기서 Karn algorithm은 9.48안에 들어오면 측정한 값에 대한 RTO를 하지 않는 것이다. (ACK이 온 경우)

그리고 다시 시작할 때는 정상적인 상황이라 초기 값 4s 가지고 다시 재시작을 한다.

 

(2) Persistence timer

: RWND = 0을 받을 때 sender에서 persistence timer를 켠다. 타이머가 만료되면 probe segment를 보낸다. reciever는 이를 받고 ACK과 RWND를 보내 준다. 이를 받은 sender는 RWND = K를 받으면, K 만큼 데이터를 보내기 시작한다. 이를 통해 deadlock을 방지할 수 있다.

 

(3) Keepalive Timer

: Client와 Server가 연결하게 되면 각자 send, recieve buffer가 생기게 된다. 연결이 끝나게 된다면 각 buffer를 반납하게 되는데, 정상적으로 종료가 되면 server에 존재하는 client와 연결한 buffer들이 해제가 된다. 하지만 비정상적으로 종료되는 경우가 있다. 이는 보통 Hardware적으로 컴퓨터까 off 될 때 발생한다. 이때 server 입장에서는 client가 연결이 되어있는 것으로 판단하여 buffer를 가지고 있는다.

Keepalive timer를 통해 server가 오랜 기간 동안 idle 상태에 있는 것을 방지한다. server가 2시간 동안 clinet로부터 segment를 받지 못하면 probe segment를 전송한다.

 

Options


TCP에서 option을 사용하면 header를 20에서부터 60 byte까지 늘릴 수 있다.

Option은 총 2가지 분류로 나누어지고, 총 7개로 구성된다.

 

Single-byte

EOP (End of option list)

 

위 그림 b에서 맨 위에 해당하는 부분은 header이다. 기본적으로는 20 byte로 구성하고, 나머지 byte에 대해 option을 사용한다. 위 경우는 3 byte에 대한 option을 사용한 경우이다. 항상 header는 1줄이 32bit로 구성되어 있다. 우리는 이를 맞추려고 노력해야 한다. 

따라서 비어있는 header 공간을 EOF를 통해 채워 준다. 이는 padding 용 byte라고 생각하면 된다. EOP는 1번만 사용될 수 있다.

 

NOP (No operation option)

어떠한 option은 시작을 1칸  뛸 때도 있다. 그 옵션을 NOP로 채운다. 또 어떠한 것은 2칸을 띄어두고 3 byte부터 시작하는 경우도 있다. 이 경우에는 NOP를 2개 설정한다. NOP도 padding이다. 또한 여러 번 쓸 수 있다.

 

Multiple-byte

MSS (Maximum segement size)

우리는 전에 CWND를 설명하면서 또는 nagle algorithm을 설명하면서 MSS라는 단어를 본 경험이 있다. nagle에서는 silly window syndrome을 방지하기 위해 buffer의 크기가 1 MSS 만큼 차게 된다면 데이터를 보냈다.

Segment의 size는 보통 560 byte이다. client와 server가 set-up 과정에서 서로 협의를 하여 이를 조절할 수 있다. MSS option은 그때 사용하는 option이다.

default MSS 값도 socket 함수를 통해 변경할 수 있고, option을 써서 MSS 값을 변경할 수 있다. connect를 통해 MSS 값의 변화를 확인해야 한다. 어떤 상황에서는 상대가 승인을 거절하여 불가능한 경우도 있다.

connect 후 변경을 하지 못하는 내용이 핵심이다.

 

Window-scale-factor option

다음은 윈도에 대한 옵션이다.

 

앞서 살펴본 모든 Kind: num은 일종의 option index라고 생각하면 되고, 외우지 않아도 된다.

위 그림은 길이가 3이고, scale factor에 값을 실어서 보낸다. 이게 왜 필요한지 알아보자.

RTT가 1초일 경우 최대 throughput은 얼마일까?

window size는 전에 min(RWND, CWND)라고 정의했다. 혼잡이 없다고 가정한다면 CWND는 계속 늘어 난다. RWND가 CWND 보다 작게 된다면 window size는 RWND에 영향을 받게 된다.

header를 보게 된다면 1칸이 16 bit이다. (1줄은 총 2칸으로 구성된다고 가정) RWND는 16 bit를 사용해서 window size 값을 전송한다. 이게 다 1로 채워지면 $2^{16}$ 이므로 총 64 Kbyte가 나온다. 따라서 남은 공간의 최대치는 64 Kbyte이다. packet은 여러 개가 한꺼번에 전송이 됨으로 보낸 데이터가 64 Kbyte면 이에 대한 ACK이 온다.

64 Kbyte를 bit로 표현하면 512Kbps가 되고, 이를 mega로 바꾸면 0.5mbps가 된다. RTT가 1초면 조금 과장된 것이고, 실제로는 이보다 작다.

우리는 현실적으로 RTT를 100ms라고 해보자. 그러면 64Kbyte를 0.1초마다 보낸다고 하면 5 Mbps가 된다. TCP를 쓰면 아무리 기가바이트를 사용해도 최대 성능이 5 Mbps라는 의미이다. 10ms여도 50 Mbps가 된다.

따라서 더 보내기 위해 window scale factor option을 사용한다. 이는 $2^{n}$으로 표현하고, size를 8배 크게 하고 싶으면 scale factor에는 3을 집어넣으면 된다.

이 option도 set-up 과정에서 진행해야 한다.

상대의 RWND가 K라고 오고 scale factor가 3이면 $K \times 2^{3}$으로 이해하면 된다.

 

Timestamp option

 

Timestamp는 RTT를 측정할 때 사용한다. 디자인은 위 그림과 같다. 빈 공간에는 NOP가 들어간다.

총 10byte로 이루어져 있고, 출발 시간과 도착 시간이 이 option에 들어간다.

 

데이터를 보내고 나면 이에 대한 ACK이 온다. ACK을 보낼 때 내가 보내는 packet의 출발 시간도 같이 보낸다. packet이 4732에 도착했다고 하면 4732 - 4720 = 12라는 연산을 통해 RTT를 쉽게 구할 수 있다.

 

우리는 32bit에 해당하는 sequence number를 쓴다. 이는 약 40억이라는 수가 된다.

Timestampt는 PAWS (Protection Against Wrapped Sequence number)에서도 사용한다. 연결을 하고 나서 보내는 packet이 매우 길면 sequence number를 다 쓰고 한 바퀴 돌아서 같은 number를 쓸 수 있다. 운이 나쁘면 packet이 혼잡해져 나중에 헷갈릴 수 있다. 따라서 이런 상황에 timestampt를 통해 출발 시간을 활용하여 구별할 수 있다.

 

SACK option

Culmulative ACK의 단점 중 하나는 ACK이 없어지면 이후에 없어진 packet들에 대한 설명을 할 수 없다. 이는 중간에 packet loss가 발생하면 ACK을 통해 없어진 packet부터 그 이후에 packet들까지 다시 재전송한다는 의미다.

reciever는 sender에게 어떤 packet만 없어졌는지 말을 해줄 수 없지만 이를 sack option을 통해 알려줄 수 있다.

SACK 옵션은 2가지 종류가 있다. (4번, 5번)

4번 SACK permitted option

Sender는 0001부터 9000까지의 packet을 보냈다고 가정하자. reciever 입장에서는 2001, 3001, 6001, 7001을 못 받은 상황이다. 이럴 때 ACK은 2001번만 보내주게 된다. 그러면 sender는 위에서 언급한 봐와 같이 2001번 이후 9000까지 다 재전송한다.

SACK은 block의 시작 주소와 끝 주소 +1로 표현한다. 이 같은 경우에는 block이 총 2개 생긴다. (5, 18)

이를 받은 sender는 3-duplicated ACK을 받게 되는데, 이를 통해 reciever가 4001번부터 6001까지 받았고, 8001 ~ 9000 까지도 잘 받은 것을 알게 된다.

이를 통해 culmulative ACK의 단점을 보완할 수 있다.

 

 

 

반응형