이병록의 개발 블로그

TCP의 흐름제어, 오류제어, 혼잡제어 예제 시나리오 본문

교육자료

TCP의 흐름제어, 오류제어, 혼잡제어 예제 시나리오

로빈 후드 이병록 2020. 6. 9. 22:11

최종 수정 일 : 2020-07-11

 

 

이 글을 작성한 이유는 다음과 같습니다.

 

 

1. TCP의 흐름제어, 오류제어, 혼잡제어를 별도의 개념을 따로따로 아는 것에 더하여 최대한 결합하여 이해해보자. (현재까지 가상 시나리오 문서는 본적이 없다.)

2. 나무도 봤으니 숲도 보자.

3. 모든 시나리오를 다루지는 않지만 대략적인 큰 흐름을 알아보자.

4. HTTP/1.x ~ HTTP/2.0의 기반인 TCP에 대해 이해를 하여, 얼마나 많은 RTT가 발생하는지 대략적으로 감을 잡아보자.

5. TCP 흐름제어, 오류제어, 혼잡제어에 대한 상세한 내용은 별도의 문서로 남기기로.

 

 

PS. 워낙에 복잡해서 오타 및 조금 미스나는 부분이 있을 수도 있습니다. 그래도 최대한 목적과 방향에 맞게 예제를 다뤄보려고 노력했습니다.

혹시나 틀린 개념을 발견하신 고수분께서는 '꼭' 리뷰 부탁드립니다.

 

 

 

TCP 흐름제어, 오류제어, 혼잡제어에 대한 개념

 

혹시나 흐름제어, 오류제어, 혼잡제어에 개념이 잘 안잡힌 경우 해당 문서를 참고하시면 도움이 될 것 같습니다.

 

https://roka88.dev/114

 

TCP의 흐름제어, 오류제어, 혼잡제어 개념에 대한 개요

최종 수정일: 2020-07-11 안녕하세요. 이번 문서는 TCP의 흐름 제어, 오류 제어, 혼잡 제어 개념과 개요에 대해 다루려고 합니다. 요즘 문서의 흐름이 좀 더 네트워크 프로토콜중 HTTP와 함께 TCP에 대��

roka88.dev

 

 

TCP 통신 가상 시나리오 (Full Process - 최대한..)

 

이 후 글은 모바일에서 보기 불편하므로, PC 또는 태블릿 환경에서 보시는 것을 추천드립니다.

그림 밑에 설명이 작성 되어있으므로, 브라우저 창을 두개 띄어서 보내시는 것이 낫습니다.

그리고 공부하는 거라면 과정을 하나씩 따라가며 그려보는 것도 좋습니다. (최대한 다양한 상황을 담아보려고 노력했습니다.)

 

정리하고 어떻게 보여줄지 고민하고 작성하고 지우고 고치고 1주일 넘게 걸림..;;;;;ㅠㅠㅠㅠ

 

실제환경에서는 수많은 TCP 알고리즘과, 구현체, 그리고 적용 옵션에 따라 
hand-shake 횟수, 확인 응답 횟수가 다르고,
오류제어 방식도 다르고, 회복방식도 다르고,
그에 따라 네트워크 혼잡도 및 RTT도 달라질 수 있습니다.

 

 

1. MSS(Maximum Segment Size)는 IPv4기준으로 1460 바이트로 가정한다. (IPv6 기준 1400 바이트)

2. 혼잡 윈도우 변수(cwnd)의 초기 값은 1로 가정한다.

3. 혼잡 윈도우의 느린 시작 임계치(Slow start threshold)는 cwnd가 4를 기준으로 가정한다..

4. 프로세스는 수신 버퍼를 최적의 상황에 따라 소비할 것으로 가정한다. 

5. PSH 플래그 패킷을 받으면, 수신자는 가능하다면 수신 버퍼의 데이터를 프로세스에 빠르게 전달하도록 노력한다.

6. 클라이언트 수신 버퍼 사이즈는 편의상 11680 bytes, 클라이언트 수신자 윈도우(rwnd)는 11680 bytes 초기값으로 가정한다.

7. 서버 수신 버퍼 사이즈는 편의상 8760 bytes, 서버 수신자 윈도우(rwnd)는 8760 bytes 초기값으로 가정한다.

8. 클라이언트는 서버에게 14600 byte를 전송할 것으로 예상하고 서버는 21900 byte를 전송할 것으로 예상한다. (HTTP 처럼 양방향(요청-응답) 예시이다.)

9. 편의상 SYN 번호는 0부터 시작하고, ACK의 번호는 40000부터 시작한다고 가정한다.

10. 흐름제어에 사용하는 윈도우 알고리즘은 슬라이딩 윈도우로 가정한다. 선택적 반복(Selective-Repeat)과 혼합되어 있다.

11. 버퍼는 Circle Queue에 가깝지만 편의상 그림으로는 일반 배열처럼 표기했다. 슬라이딩 윈도우가 close, open 되는 방식을 잊지 말아야 한다.

12. 송신측에서 발생하는 어리석은 윈도 신드롬을 해결하기 위해 네이글 알고리즘을 가정하나, 세그먼트를 MSS 만큼 크기로 전송할 것으로 가정하므로 시나리오상 큰 영향은 없다.

13. 수신측에서 발생하는 어리석은 윈도 신드롬을 해결하기 위해 클라크의 해결방법(Clark's solution)사용하지 않는다고 가정한다. 이말은, 지연 확인응답 방식을 사용하지 않으며, 수신 버퍼가 여유가 있을 때 까지 rwnd를 0으로 통보하는 방식을 사용하지 않는다. 바로바로 보낸다.

14. 커넥션 설립 시 오류제어를 위해 확인 응답 방식을 송신자, 수신자 둘 다 선택적 확인 응답 방식(SACK)으로 설립하고 설정했다고 가정한다.

15. 빠른 재전송빠른 회복 알고리즘을 적용한다.(Reno TCP를 기준으로 하도록 노력하였다.)

16. 패킷 손실이 아닌 이상, 송신자가 보낸 순서대로 수신자가 받는다고 가정한다. (실제로는 보낸 순서에 맞지 않게 세그먼트가 도착할 수 있다.)

17. RTO, 영속 타이머 등의 시간까지 계산하지는 않는다..

 

 

 

커넥션 설립 (3 Hand-Shake)

 

그림의 번호와 글의 번호와 과정이 일치하므로 잘 따라와야 한다.

 

(1) (클라이언트측) 클라이언트는 서버와 커넥션 설립을 위해 SYN 플래그와 함께 임의의 시퀸스 번호(seqNo)를 0으로 초기화하여 전송한다.

 

(2) (서버측) SYN 플래그 패킷을 받은 서버는

- 서버 수신 버퍼 8760 byte로 초기화하고

- 클라이언트에게 서버 수신 윈도우(rwnd)를 8760 bytes 이라고 설정하고,

- 클라이언트 측에 보낼 확인 응답 번호(ackNo) = seqNo + 1의 값으로 하고,

- 서버측의 임의의 시퀸스번호(seqNo)를 40000으로 설정하고,

- SYN, ACK 플래그와 같이 전송한다.

 

(3) (클라이언트측) SYN, ACK 플래그 패킷을 받은 클라이언트는 일시적으로 서버의 수신 윈도우(rwnd) 7300로 저장하고,

- 클라이언트 수신 버퍼를 11680 byte로 초기화

- 서버에게 클라이언트 수신 윈도우(rwnd)가 11680 bytes 이라고 설정하고,

- 서버로 부터 받은 ackNo를 seqNo로 설정하고,

- 서버측에 보낼 확인 응답번호(ackNo) = seqNo + 1의 값으로 하고, 

- ACK 플래그와 같이 전송한다.

 

(4) (서버측) ACK 플래그 패킷을 받은 서버는 일시적으로 클라이언트의 수신 윈도우(rwnd) 11680로 저장하고,

- 클라이언트에게 데이터를 수신할 준비를 한다.

 

 

이 과정에 패킷이 누락된 것이 아니면 정상적으로 Hand-Shake를 했다고 볼 수 있고, 커넥션이 설립되었다고 할 수 있다.

 

 

 

 

클라이언트측 데이터 전송 과정은? - 정상시나리오

 

(5) (클라이언트측)

- 클라이언트 측에서 보낼 데이터는 14600 bytes이다.

 

(6) (클라이언트측)

- 송신자(현재는 클라이언트)는 전송할 데이터를 세그먼트화 하여 수신자(현재는 서버)에게 보낼준비를 한다. 해당 시나리오에서는 편의상 MSS(1460 bytes)를 기준으로 세그먼트로 나누었다.

 

(7) (클라이언트측)

- 클라이언트 송신 윈도우를 초기화 한다.

- 이 시나리오에서는 cwnd 변수를 1로 지정하였다. (1 cwnd = 1 MSS = 1460 bytes)

- 커넥션 설립 시 서버로 부터 받은 서버 수신 윈도우(rwnd) 8760 와 혼잡 윈도우(cwnd)를 비교 하여 클라이언트 송신 윈도우(awnd)를 초기화 한다.

- 클라이언트 송신 윈도우(awnd)를 1460 bytes(minimum(서버 수신 윈도우(rwnd) 8760 bytes, 혼잡 윈도우(cwnd) 1 * MSS))로 변경한다.

- 고로 최초 클라이언트 송신 윈도우(awnd) 크기는 1460 bytes이다.

- 클라이언트는 서버에게 ACK플래그 패킷과 함께 커넥션 설립 때 서버에게 확인 응답 시 보낸 seqNo, ackNo 동일하게 설정하여, 데이터와 함께 전송한다.    

- TCP 느린시작(slow start)이다.

 

(8) (서버측)

- 서버는 클라이언트에게 1460 bytes의 데이터를 수신 하면 서버 수신 버퍼에 데이터를 저장 후,

- 새로운 서버 수신 윈도우(rwnd)7300 bytes(기존 서버 수신 윈도우(rwnd) 8760 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(40001), ackNo(1461 = seqNo(1) + data size(1460)), 서버 수신 윈도우(rwnd) 7300으로 보낸다.

 

(9) (클라이언트측)

- 클라이언트는 서버로 부터 확인 응답을 받은 후

- 정상 수신된 바이트 크기(1460 bytes)만큼, 클라이언트 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 점선으로 표기된 segment는 정상적으로 전송되었다는 표시이다.

- 혼잡 윈도우(cwnd)는 ACK 당 cwnd = cwnd(초기값 1) + 1 메커니즘을 가정으로 혼잡 윈도우(cwnd)는 2가 된다.

- 서버로 부터 받은 서버 수신 윈도우(rwnd)는 7300 bytes이다. 

- 클라이언트 송신 윈도우(awnd)를 2920 bytes(minimum(서버 수신 윈도우(rwnd) 8760 bytes, 혼잡 윈도우(cwnd) 2 * MSS))로 변경한다.

- 재 계산된 클라이언트 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(10) (클라이언트측)

- MSS가 (IPv4 1460 byte) 이며, 클라이언트 송신 윈도우(awnd)가 2920 bytes 이므로 서버의 확인 응답 없이 2개의 세그먼트를 전송할 수 있다.

클라이언트는 서버에게  ACK 플래그 패킷과 함께 seqNo(ackNo 1461), ackNo(40001), 데이터를 1460 bytes를 보낸다.

 

(11) (클라이언트측)

- 클라이언트는 서버에게 ACKPSH 플래그 패킷과 함께 seqNo(2921 = 1461 + 1460), ackNo(40001), 데이터를 1460 bytes를 보낸다.

 

(12) (서버측)

- 서버는 클라이언트에게 1460 bytes의 데이터를 수신 하면 서버 수신 버퍼에 데이터를 저장 후,

- 새로운 서버 수신 윈도우(rwnd) 5840 bytes(기존 서버 수신 윈도우(rwnd) 7300 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(40001), ackNo(2921) = seqNo(1461) + data size(1460), 서버 수신 윈도우(rwnd) 7300으로 보낸다.

 

(13) (서버측)

- 서버는 클라이언트에게 1460 bytes의 데이터를 수신 하면 서버 수신 버퍼에 데이터를 저장 후,

- 새로운 서버 수신 윈도우(rwnd)를 4380 bytes(기존 서버 수신 윈도우(rwnd) 5840 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(40001), ackNo(4381) = seqNo(2921) + data size(1460), 서버 수신 윈도우(rwnd) 7300으로 보낸다.

 

 

(14) (클라이언트측)

- 클라이언트는 서버로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 클라이언트 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 혼잡 윈도우(cwnd)는 ACK 당 cwnd = cwnd(기존 2) + 1 메커니즘을 가정으로 혼잡 윈도우(cwnd)는 3가 된다.

- 서버로 부터 받은 서버 수신 윈도우(rwnd)는 5840 bytes이다. 

- 클라이언트 송신 윈도우(awnd)를 5840 bytes(minimum(서버 수신 윈도우(rwnd) 5840 bytes, 혼잡 윈도우(cwnd) 3 * MSS))로 변경한다.

- 재 계산된 클라이언트 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(15) (클라이언트측)

- 클라이언트는 서버로 부터 확인 응답을 받은 후 정상 수신된 바이트 크기(1460 bytes)만큼 클라이언트 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 혼잡 윈도우(cwnd)는 ACK 당 cwnd = cwnd(기존 3) + 1 메커니즘을 가정으로 혼잡 윈도우(cwnd)는 4가 된다.

- 서버로 부터 받은 서버 수신 윈도우(rwnd)는 4380 bytes이다. 

- 클라이언트 송신 윈도우(awnd)를 4380 bytes(minimum(서버 수신 윈도우(rwnd) 4380 bytes, 혼잡 윈도우(cwnd) 4 * MSS))로 변경한다.

- 재 계산된 클라이언트 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

 

 

 

(16) (서버측)

- 스케쥴링 또는 상황에 따라 서버 수신 버퍼에 담겨 있는 데이터를 프로세스로 전달한다. 정상적인 패킷 순서이므로 전달 할 수 있다.

- 서버측의 여유로운 상황에 의해 서버 수신 윈도우(rwnd)가 8760 bytes로 변경되었다.

- 참고로 서버 수신 윈도우(rwnd)서버 수신 버퍼 사이즈를 초과할 수 없다. 

- rwnd = buffer size - number of waiting bytes to be pulled

 

(17) (클라이언트측)

- MSS가 (IPv4 1460 bytes) 이며, 클라이언트 송신 윈도우(awnd)4380 bytes이므로 서버의 확인 응답 없이 3개의 세그먼트를 전송할 수 있다.

 ACK 플래그 패킷과 함께 seqNo(ackNo 4381), ackNo(40001), 데이터를 1460 bytes를 보낸다.

 

(18) (클라이언트측) 클라이언트는 서버에게 

 ACK 플래그 패킷과 함께 seqNo를 5841 = (4381 + 1460), ackNo를 40001, 데이터를 1460 bytes를 보낸다.

 

(19) (클라이언트측) 클라이언트는 서버에게 

 ACKPSH 플래그 패킷과 함께 seqNo를 7301 = (5841 + 1460), ackNo를 40001, 데이터를 1460 bytes를 보낸다.

 

(20) (서버측)

- 서버는 클라이언트에게 1460 bytes의 데이터를 수신 하면 서버 수신 버퍼에 데이터를 저장 후,

- 새로운 서버 수신 윈도우(rwnd)를 7300 bytes(기존 서버 수신 윈도우(rwnd) 8760 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(40001), ackNo(5841) = seqNo(4380) + data size(1460), 서버 수신 윈도우(rwnd) 7300으로 보낸다.

 

(21) (서버측)

- 서버는 클라이언트에게 1460 bytes의 데이터를 수신 하면 서버 수신 버퍼에 데이터를 저장 후,

- 새로운 서버 수신 윈도우(rwnd)를 5840 bytes(기존 서버 수신 윈도우(rwnd) 7300 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(40001), ackNo(7301) = seqNo(5841) + data size(1460), 서버 수신 윈도우(rwnd) 5840 으로 보낸다.

 

(22) (서버측)

- 서버는 클라이언트에게 1460 bytes의 데이터를 수신 하면 서버 수신 버퍼에 데이터를 저장 후,

- 새로운 서버 수신 윈도우(rwnd)5840 bytes(기존 서버 수신 윈도우(rwnd) 5840 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 스케쥴링 또는 상황에 따라 서버 수신 버퍼에 담겨 있는 데이터를 프로세스로 전달한다. 정상적인 패킷 순서이므로 전달 할 수 있다.

- 서버측의 여유로운 상황에 의해 서버 수신 윈도우(rwnd)가 8760 bytes로 변경되었다.

- 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(40001), ackNo(8761) = seqNo(7301) + data size(1460), 서버 수신 윈도우(rwnd) 8760으로 보낸다.

 

(23) (클라이언트측)

클라이언트는 서버로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 클라이언트 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 혼잡 윈도우(cwnd)가 4가 되었으므로 시나리오에서 얘기한대로 혼잡 회피 방식으로 변경되며, 계산 방식을 가산 증가 방식(cwnd = cwnd + 1/cwnd)으로 변경한다.

- 서버로 부터 받은 서버 수신 윈도우(rwnd)는 7300 bytes이다. 

클라이언트 송신 윈도우(awnd)를 6205 bytes(minimum(서버 수신 윈도우(rwnd) 7300 bytes, 혼잡 윈도우(cwnd) 4.25 * MSS))로 변경한다.

- 재 계산된 클라이언트 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(24) (클라이언트측)

클라이언트는 서버로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 클라이언트 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 서버로 부터 받은 서버 수신 윈도우(rwnd)는 5840 bytes이다. 

클라이언트 송신 윈도우(awnd)5840 bytes(minimum(서버 수신 윈도우(rwnd) 5840 bytes, 혼잡 윈도우(cwnd) 4.485 * MSS))로 변경한다.

- 재 계산된 클라이언트 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(25) (클라이언트측)

클라이언트는 서버로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 클라이언트 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 서버로 부터 받은 서버 수신 윈도우(rwnd)는 8760 bytes이다. 

클라이언트 송신 윈도우(awnd) 6872 bytes(minimum(서버 수신 윈도우(rwnd) 8760 bytes, 혼잡 윈도우(cwnd) 4.707 * MSS))로 변경한다.

- 재 계산된 클라이언트 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

 

 

(26) (클라이언트측)

- MSS가 (IPv4 1460 bytes) 이며, 클라이언트 송신 윈도우(awnd) 6872 bytes이므로 서버의 확인 응답 없이 4개의 세그먼트를 전송할 수 있다. (정확히 6872 bytes를 보낼 수 있으나, 이번 시나리오에서는 MSS 단위로 보내기로 한다)

 ACK 플래그 패킷과 함께 seqNo(ackNo 8761), ackNo(40001), 데이터를 1460 bytes를 보낸다.

 

(27) (클라이언트측) 클라이언트는 서버에게 

 ACK 플래그 패킷과 함께 seqNo를 10221 = (8761 + 1460), ackNo를 40001, 데이터를 1460 bytes를 보낸다.

 

(28) (클라이언트측) 클라이언트는 서버에게 

 ACK 플래그 패킷과 함께 seqNo를 11681 = (10221 + 1460), ackNo를 40001, 데이터를 1460 bytes를 보낸다.

 

(29) (클라이언트측) 클라이언트는 서버에게 

 ACKPSH 플래그 패킷과 함께 seqNo를 13141 = (11681 + 1460), ackNo를 40001, 데이터를 1460 bytes를 보낸다.

 

(30) (서버측)

- 서버는 클라이언트에게 1460 bytes의 데이터를 수신 하면 서버 수신 버퍼에 데이터를 저장 후,

- 새로운 서버 수신 윈도우(rwnd)를 7300 bytes(기존 서버 수신 윈도우(rwnd) 8760 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(40001), ackNo(10221) = seqNo(8761) + data size(1460), 서버 수신 윈도우(rwnd) 7300으로 보낸다.

 

(31) (서버측)

- 서버는 클라이언트에게 1460 bytes의 데이터를 수신 하면 서버 수신 버퍼에 데이터를 저장 후,

- 새로운 서버 수신 윈도우(rwnd)를 5840 bytes(기존 서버 수신 윈도우(rwnd) 7300 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(40001), ackNo(11681) = seqNo(10221) + data size(1460), 서버 수신 윈도우(rwnd) 5840으로 보낸다.

 

(32) (서버측)

- 서버는 클라이언트에게 1460 bytes의 데이터를 수신 하면 서버 수신 버퍼에 데이터를 저장 후,

- 새로운 서버 수신 윈도우(rwnd)를 4830 bytes(기존 서버 수신 윈도우(rwnd) 5840 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(40001), ackNo(13141) = seqNo(11681) + data size(1460), 서버 수신 윈도우(rwnd) 4830으로 보낸다.

 

(33) (서버측)

- 서버는 클라이언트에게 1460 bytes의 데이터를 수신 하면 서버 수신 버퍼에 데이터를 저장 후,

- 새로운 서버 수신 윈도우(rwnd)를 2920 bytes(기존 서버 수신 윈도우(rwnd) 4830 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 스케쥴링 또는 상황에 따라 서버 수신 버퍼에 담겨 있는 데이터를 프로세스로 전달한다. 정상적인 패킷 순서이므로 전달 할 수 있다.

- 서버측의 여유로운 상황에 의해 서버 수신 윈도우(rwnd)가 8760 bytes로 변경되었다.

- 참고로 서버 수신 윈도우(rwnd)는 서버 수신 버퍼 사이즈를 초과할 수 없다. 

- 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(40001), ackNo(14601) = seqNo(13141) + data size(1460), 서버 수신 윈도우(rwnd) 8760으로 보낸다.

 

(34) (클라이언트측)

클라이언트는 서버로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 클라이언트 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 서버로 부터 받은 서버 수신 윈도우(rwnd)는 7300 bytes이다. 

클라이언트 송신 윈도우(awnd)를 7181 bytes(minimum(서버 수신 윈도우(rwnd) 7300 bytes, 혼잡 윈도우(cwnd) 4.919 * MSS))로 변경한다.

- 재 계산된 클라이언트 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(35) (클라이언트측)

클라이언트는 서버로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 클라이언트 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 서버로 부터 받은 서버 수신 윈도우(rwnd)는 5840 bytes이다. 

클라이언트 송신 윈도우(awnd)5840 bytes(minimum(서버 수신 윈도우(rwnd) 5840 bytes, 혼잡 윈도우(cwnd) 5.122 * MSS))로 변경한다.

- 재 계산된 클라이언트 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(36) (클라이언트측)

클라이언트는 서버로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 클라이언트 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 서버로 부터 받은 서버 수신 윈도우(rwnd)는 4830 bytes이다. 

클라이언트 송신 윈도우(awnd)4830 bytes(minimum(서버 수신 윈도우(rwnd) 4830 bytes, 혼잡 윈도우(cwnd) 5.317 * MSS))로 변경한다.

- 재 계산된 클라이언트 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(37) (클라이언트측)

클라이언트는 서버로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 클라이언트 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 서버로 부터 받은 서버 수신 윈도우(rwnd)는 8760 bytes이다. 

클라이언트 송신 윈도우(awnd)8037 bytes(minimum(서버 수신 윈도우(rwnd) 8760 bytes, 혼잡 윈도우(cwnd) 5.505 * MSS))로 변경한다.

- 재 계산된 클라이언트 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

 

서버측 데이터 전송 과정은?

 

 

 

(39) (서버측)

- 송신자(현재는 서버)는 전송할 데이터를 세그먼트화 하여 수신자(현재는 클라이언트)에게 보낼준비를 한다. 해당 시나리오에서는 편의상 MSS(1460 bytes)를 기준으로 세그먼트로 나누었다.

 

(40) (서버측)

- 서버 송신 윈도우를 초기화 한다.

- 이 시나리오에서는 cwnd 변수를 1로 지정하였다. (1 cwnd = 1 MSS = 1460 bytes)

- 커넥션 설립 시 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd) 11680 와 혼잡 윈도우(cwnd)를 비교 하여 서버 송신 윈도우(awnd)를 초기화 한다.

서버 송신 윈도우(awnd)를 1460 bytes(minimum(클라이언트 수신 윈도우(rwnd) 11680 bytes, 혼잡 윈도우(cwnd) 1 * MSS))로 변경한다.

- 고로 최초 서버 송신 윈도우(awnd) 크기는 1460 bytes이다.

서버는 클라이언트에게 ACKPSH 플래그 패킷과 함께 커넥션 설립 때 클라이언트에게 확인 응답 시 보낸 seqNo, ackNo 동일하게 설정하여, 데이터와 함께 전송한다.

- TCP 느린시작(slow start)이다.

 

(41) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd) 10220 bytes(기존 클라이언트 수신 윈도우(rwnd) 11680 bytes - 서버에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 스케쥴링 또는 상황에 따라 클라이언트 수신 버퍼에 담겨 있는 데이터를 프로세스로 전달한다. 정상적인 패킷 순서이므로 전달 할 수 있다.

- 클라이언트의 여유로운 상황에 의해 클라이언트 수신 윈도우(rwnd)11680 bytes로 변경되었다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(41461 = seqNo(40001) + data size(1460)), 클라이언트 수신 윈도우(rwnd) 11680으로 보낸다.

 

(42) (서버측)

- 서버는 클라이언트로 부터 확인 응답을 받은 후

- 정상 수신된 바이트 크기(1460 bytes)만큼, 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 점선으로 표기된 segment는 정상적으로 전송되었다는 표시이다.

- 혼잡 윈도우(cwnd)는 ACK 당 cwnd = cwnd(초기값 1) + 1 메커니즘을 가정으로 혼잡 윈도우(cwnd)는 2가 된다.

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)는 11680 bytes이다. 

- 서버 송신 윈도우(awnd)를 2920 bytes(minimum(클라이언트 수신 윈도우(rwnd) 11680 bytes, 혼잡 윈도우(cwnd) 2 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

 

 

(43) (서버측)

- MSS가 (IPv4 1460 bytes) 이며, 서버 송신 윈도우(awnd) 2920 bytes이므로 클라이언트의 확인 응답 없이 2개의 세그먼트를 전송할 수 있다.

 ACK, 플래그 패킷과 함께 seqNo(ackNo 41461), ackNo(14601), 데이터를 1460 bytes를 보낸다.

 

(44) (서버측) 서버는 클라이언트에게 

 ACKPSH 플래그 패킷과 함께 seqNo를 42921 = (41461 + 1460), ackNo를 14601, 데이터를 1460 bytes를 보낸다.

 

(45) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 10220 bytes(기존 클라이언트 수신 윈도우(rwnd) 11680 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(42921) = seqNo(41461) + data size(1460), 클라이언트 수신 윈도우(rwnd) 10220 으로 보낸다.

 

(46) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 8760 bytes(기존 클라이언트 수신 윈도우(rwnd) 10220 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(44381) = seqNo(42921) + data size(1460), 클라이언트 수신 윈도우(rwnd) 8760 으로 보낸다.

 

(47) (서버측)

서버는 클라이언트로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)는 10220 bytes이다. 

- 서버 송신 윈도우(awnd)를 4380 bytes(minimum(클라이언트 수신 윈도우(rwnd) 10220 bytes, 혼잡 윈도우(cwnd) 3 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(48) (서버측)

서버는 클라이언트로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)는 8760 bytes이다. 

- 서버 송신 윈도우(awnd)를 5840 bytes(minimum(클라이언트 수신 윈도우(rwnd) 8760 bytes, 혼잡 윈도우(cwnd) 4 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(49) (서버측)

- MSS가 (IPv4 1460 bytes) 이며, 서버 송신 윈도우(awnd) 5840 bytes이므로 클라이언트의 확인 응답 없이 4개의 세그먼트를 전송할 수 있다.

 ACK, 플래그 패킷과 함께 seqNo(ackNo 44381), ackNo(14601), 데이터를 1460 bytes를 보낸다.

 

(50) (서버측) 서버는 클라이언트에게 

 ACK 플래그 패킷과 함께 seqNo를 45841 = (44381 + 1460), ackNo를 14601, 데이터를 1460 bytes를 보낸다.

 

(51) (서버측) 서버는 클라이언트에게 

 ACK 플래그 패킷과 함께 seqNo를 47301 = (45841 + 1460), ackNo를 14601, 데이터를 1460 bytes를 보낸다.

 

(52) (서버측) 서버는 클라이언트에게 

 ACKPSH 플래그 패킷과 함께 seqNo를 48761 = (47301 + 1460), ackNo를 14601, 데이터를 1460 bytes를 보낸다.

 

(53) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 7300 bytes(기존 클라이언트 수신 윈도우(rwnd) 8760 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(45851) = seqNo(44381) + data size(1460), 클라이언트 수신 윈도우(rwnd) 7300 으로 보낸다.

 

(54) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 5840 bytes(기존 클라이언트 수신 윈도우(rwnd) 7300 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(47301) = seqNo(45851) + data size(1460), 클라이언트 수신 윈도우(rwnd) 5840 으로 보낸다.

 

(55) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 4380 bytes(기존 클라이언트 수신 윈도우(rwnd) 5840 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(48761) = seqNo(47301) + data size(1460), 클라이언트 수신 윈도우(rwnd) 4380 으로 보낸다.

 

(56) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 5840 bytes(기존 클라이언트 수신 윈도우(rwnd) 7300 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 스케쥴링 또는 상황에 따라 클라이언트 수신 버퍼에 담겨 있는 데이터를 프로세스로 전달한다. 정상적인 패킷 순서이므로 전달 할 수 있다.

- 클라이언트측의 여유로운 상황에 의해 클라이언트 수신 윈도우(rwnd) 11680 bytes로 변경되었다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(50221) = seqNo(48761) + data size(1460), 클라이언트 수신 윈도우(rwnd) 11680 으로 보낸다.

 

(57) (서버측)

서버는 클라이언트로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)는 7300 bytes이다. 

혼잡 윈도우(cwnd)가 4가 되었으므로 시나리오에서 얘기한대로 혼잡 회피 방식으로 변경되며, 계산 방식을 가산 증가 방식(cwnd = cwnd + 1/cwnd)으로 변경한다.

- 서버 송신 윈도우(awnd)를 6205 bytes(minimum(클라이언트 수신 윈도우(rwnd) 7300 bytes, 혼잡 윈도우(cwnd) 4.25 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(58) (서버측)

서버는 클라이언트로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)5840 bytes이다. 

서버 송신 윈도우(awnd)를 5840 bytes(minimum(클라이언트 수신 윈도우(rwnd) 5840 bytes, 혼잡 윈도우(cwnd) 4.485 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(59) (서버측)

서버는 클라이언트로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)4380 bytes이다. 

서버 송신 윈도우(awnd)4380 bytes(minimum(클라이언트 수신 윈도우(rwnd) 4380 bytes, 혼잡 윈도우(cwnd) 4.707 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(60) (서버측)

서버는 클라이언트로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)11680 bytes이다. 

서버 송신 윈도우(awnd)7181 bytes(minimum(클라이언트 수신 윈도우(rwnd) 11680 bytes, 혼잡 윈도우(cwnd) 4.919 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

 

 

송신시 세그먼트 손실 시나리오

 

(61) (서버측)

- MSS가 (IPv4 1460 bytes) 이며, 서버 송신 윈도우(awnd) 7181 bytes이므로 클라이언트의 확인 응답 없이 4개의 세그먼트를 전송할 수 있다. (정확히 7181 bytes를 보낼 수 있으나, 이번 시나리오에서는 MSS 단위로 보내기로 한다)

 ACK 플래그 패킷과 함께 seqNo(ackNo 50221), ackNo(14601), 데이터를 1460 bytes를 보낸다.

 

(62) (서버측) 서버는 클라이언트에게 

 ACK 플래그 패킷과 함께 seqNo를 51681 = (50221 + 1460), ackNo를 14601, 데이터를 1460 bytes를 보낸다.

 

(63) (서버측) 서버는 클라이언트에게 

 ACK 플래그 패킷과 함께 seqNo를 53414 = (51681 + 1460), ackNo를 14601, 데이터를 1460 bytes를 보낸다.

 

(64) (서버측) 서버는 클라이언트에게 

 ACKPSH 플래그 패킷과 함께 seqNo를 54601 = (53414 + 1460), ackNo를 14601, 데이터를 1460 bytes를 보낸다.

 

(65) (클라이언트측) 세그먼트 seqNo가 맞지 않음

- 클라이언트가 수신해야 할 세그먼트 seqNo는 50221이나 실제로 51681 도착했다.

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 순서에 맞지는 않으나 일단 클라이언트 수신 버퍼에 데이터를 저장 후, 순서에 맞지 않는 세그먼트라고 체크한다.

- 새로운 클라이언트 수신 윈도우(rwnd)를 10220 bytes(기존 클라이언트 수신 윈도우(rwnd) 11680 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 seqNo 50221 세그먼트가 오길 기다리며 정상적인 수신 패킷은 50221로 보내야 한다고 알리기 위해, 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(50221) , 클라이언트 수신 윈도우(rwnd) 10220 으로 보낸다.

 

(66) (클라이언트측) 세그먼트 seqNo가 맞지 않음

- 클라이언트가 수신해야 할 세그먼트 seqNo는 50221이나 실제로 53414 도착했다.

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 순서에 맞지는 않으나 일단 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)8760 bytes(기존 클라이언트 수신 윈도우(rwnd) 10220 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 seqNo 50221 세그먼트가 오길 기다리며 정상적인 수신 패킷은 50221로 보내야 한다고 알리기 위해, 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(50221) , 클라이언트 수신 윈도우(rwnd) 8760 으로 보낸다.

 

(67) (클라이언트측) 세그먼트 seqNo가 맞지 않음

- 클라이언트가 수신해야 할 세그먼트 seqNo는 50221이나 실제로 54601 도착했다.

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 순서에 맞지는 않으나 일단 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 7300 bytes(기존 클라이언트 수신 윈도우(rwnd) 8760 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 seqNo 50221 세그먼트가 오길 기다리며 정상적인 수신 패킷은 50221로 보내야 한다고 알리기 위해, 서버는 클라이언트에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(50221) , 클라이언트 수신 윈도우(rwnd) 7300 으로 보낸다.

 

(68) (서버측)

서버는 클라이언트로 seqNo(14601), ackNo(51681) 기대했으나, seqNo(14601), ackNo(50221)로 수신되었다.

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)는 10220 bytes이다. 

- 타임아웃은 아니라고 가정한다.

- 첫 번째 중복(first duplication) 확인 응답을 수신하였다.

 

(69) (서버측)

서버는 클라이언트로 seqNo(14601), ackNo(53414) 기대했으나, seqNo(14601), ackNo(50221)로 수신되었다.

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)는 8760 bytes이다. 

- 타임아웃은 아니라고 가정한다.

- 두 번째 중복(second duplication) 확인 응답을 수신하였다.

 

(70) (서버측)

서버는 클라이언트로 seqNo(14601), ackNo(53414) 기대했으나, seqNo(14601), ackNo(50221)로 수신되었다.

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)는 7300 bytes이다. 

- 타임아웃은 아니라고 가정한다.

- 세 번째 중복(third duplication) 확인 응답을 수신하였다. 그러므로 서버측은 빠른 회복 상태로 돌입한다.

- 기존 cwnd = 4.919 에서  ssthresh = cwnd / 2, cwnd = ssthresh + 3 계산을 통해, 새로운 cwnd = 5.459, ssthresh = 2.459 변경된다.

서버 송신 윈도우(awnd)7300 bytes(minimum(클라이언트 수신 윈도우(rwnd) 7300 bytes, 혼잡 윈도우(cwnd) 5.459 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

- RTO 타이머는 Restart가 되며, 손실된 패킷을 전송하기 위해 

 ACK 플래그 패킷과 함께 seqNo를 50221 , ackNo를 14601, 데이터를 1460 bytes를 빠른 재전송(fast retransmission)한다.

 

(71) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후, 순서에 맞지 않는 세그먼트를 재정렬한다. (별도의 버퍼 또는 체크를 통해)

- 새로운 클라이언트 수신 윈도우(rwnd)를 5840 bytes(기존 클라이언트 수신 윈도우(rwnd) 7300 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(56061), 클라이언트 수신 윈도우(rwnd) 5840 으로 보낸다.

 

(72) (서버측)

- 서버는 클라이언트로 부터 타임아웃이 아닌 상황에서 새로운 확인 응답(new ACK)를 받았으므로, 혼잡 회피 상태로 변경된다.

- 기존 cwnd = 5.459 에서 cwnd = ssthresh 계산을 통해, 새로운 cwnd = 2.459로 변경된다.

서버는 클라이언트로 부터 확인 응답으로 ackNo(56061)을 받았고 확인 응답은 누적이기 때문에 이전에 보낸 패킷은 정상 수신되었다고 판단하며 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)5840 bytes이다. 

서버 송신 윈도우(awnd)를 3590 bytes(minimum(클라이언트 수신 윈도우(rwnd) 5840 bytes, 혼잡 윈도우(cwnd) 2.459 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

 

 

 

확인 응답 세그먼트 손실 시나리오

 

 

 

(73) (서버측)

- MSS가 (IPv4 1460 bytes) 이며, 서버 송신 윈도우(awnd) 3538 bytes이므로 클라이언트의 확인 응답 없이 2개의 세그먼트를 전송할 수 있다. (정확히 3538 bytes를 보낼 수 있으나, 이번 시나리오에서는 MSS 단위로 보내기로 한다)

 ACK 플래그 패킷과 함께 seqNo(ackNo 56061), ackNo(14601), 데이터를 1460 bytes를 보낸다.

 

(74) (서버측) 서버는 클라이언트에게 

ACKPSH 플래그과 함께 seqNo를 57521 = (56061 + 1460), ackNo를 14601, 데이터를 1460 bytes를 보낸다.

 

(75) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 4380 bytes(기존 클라이언트 수신 윈도우(rwnd) 5840 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(57521) = seqNo(56061) + data size(1460), 클라이언트 수신 윈도우(rwnd) 7300 으로 보낸다.

 

(76) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 2920 bytes(기존 클라이언트 수신 윈도우(rwnd) 4380 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 스케쥴링 또는 상황에 따라 클라이언트 수신 버퍼에 담겨 있는 데이터를 프로세스로 전달한다. 정상적인 패킷 순서이므로 전달 할 수 있다.

클라이언트의 여유로운 상황에 의해 클라이언트 수신 윈도우(rwnd)가 11680 bytes로 변경되었다.

클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(58981) = seqNo(57521) + data size(1460), 클라이언트 수신 윈도우(rwnd) 11680 으로 보낸다.

 

(77) (서버측) 클라이언트로 부터 확인 응답을 받지 못함

서버는 클라이언트로 ackNo(57521), ackNo(58951) 기대했으나 확인 응답을 받지 못했다.

- RTO 타이머는 다시 time-out/restart가 되며

- 혼잡 회피 상태에서 느린 시작 상태로 변경되고, 기존의 cwnd 2.459 이므로, ssthresh는 1.229(cwnd/2)로 변경되고 cwnd는 1로 변경된다.

서버 송신 윈도우(awnd)를 1460 bytes(minimum(클라이언트 수신 윈도우(rwnd) 5840 bytes, 혼잡 윈도우(cwnd) 1 * MSS))로 변경한다.

- 서버는 다시한번 ACK 플래그 패킷과 함께 seqNo(ackNo 56061), ackNo(14601), 데이터를 1460 bytes를 보낸다.

 

(78) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면, 동일한 패킷을 받았으므로 폐기처리하며

클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(58981), 클라이언트 수신 윈도우(rwnd) 11680 으로 보낸다.

 

(79) (서버측)

서버는 클라이언트로 부터 확인 응답을 받은 후, seqNo 58950 까지 잘 전송되었다고 판단하고 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)는 11680 bytes이다. 

서버 송신 윈도우(awnd)를 2920 bytes(minimum(클라이언트 수신 윈도우(rwnd) 11680 bytes, 혼잡 윈도우(cwnd) 2* MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

 

서버측 남은 패킷 전송

 

 

(80) (서버측)

- MSS가 (IPv4 1460 bytes) 이며, 서버 송신 윈도우(awnd) 2920 bytes이므로 클라이언트의 확인 응답 없이 2개의 세그먼트를 전송할 수 있다. 

 ACK 플래그 패킷과 함께 seqNo(ackNo 58981), ackNo(14601), 데이터를 1460 bytes를 보낸다.

 

(81) (서버측) 서버는 클라이언트에게 

 ACKPSH 플래그 패킷과 함께 seqNo를 60441 = (58981 + 1460), ackNo를 14601, 데이터를 1460 bytes를 보낸다.

 

(82) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 10220 bytes(기존 클라이언트 수신 윈도우(rwnd) 11680 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(42921) = seqNo(41461) + data size(1460), 클라이언트 수신 윈도우(rwnd) 10220 으로 보낸다.

 

(83) (클라이언트측)

- 클라이언트는 서버에게 1460 bytes의 데이터를 수신 하면 클라이언트 수신 버퍼에 데이터를 저장 후,

- 새로운 클라이언트 수신 윈도우(rwnd)를 8760 bytes(기존 클라이언트 수신 윈도우(rwnd) 10220 bytes - 클라이언트에게 받은 데이터 1460 bytes) 로 윈도우를 닫기(왼쪽 커서가 오른쪽으로 이동)하여 변경한다.

- 클라이언트는 서버에게 ACK 플래그 패킷과 함께 seqNo(14601), ackNo(44381) = seqNo(42921) + data size(1460), 클라이언트 수신 윈도우(rwnd) 8760 으로 보낸다.

 

(84) (서버측)

서버는 클라이언트로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)는 10220 bytes이다. 

혼잡 윈도우(cwnd)가 2가 되었으므로(현재 ssthresh = 1.229)  혼잡 회피 방식으로 변경되며, 계산 방식을 가산 증가 방식(cwnd = cwnd + 1/cwnd)으로 변경한다.

- 서버 송신 윈도우(awnd)를 10220 bytes(minimum(클라이언트 수신 윈도우(rwnd) 10220 bytes, 혼잡 윈도우(cwnd) 2.5 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다.

 

(85) (서버측)

서버는 클라이언트로 부터 확인 응답을 받은 후, 정상 수신된 바이트 크기(1460 bytes)만큼 서버 송신 윈도우(awnd)를 열기, 닫기(오른쪽 커서가 오른쪽, 왼쪽 커서가 오른쪽으로 이동)를 한다. 

- 클라이언트로 부터 받은 클라이언트 수신 윈도우(rwnd)는 11680 bytes이다. 

혼잡 윈도우(cwnd)가 2가 되었으므로(현재 ssthresh = 1.229)  혼잡 회피 방식으로 변경되며, 계산 방식을 가산 증가 방식(cwnd = cwnd + 1/cwnd)으로 변경한다.

- 서버 송신 윈도우(awnd)를 4234 bytes(minimum(클라이언트 수신 윈도우(rwnd) 11680 bytes, 혼잡 윈도우(cwnd) 2.9 * MSS))로 변경한다.

- 재 계산된 서버 송신 윈도우(awnd)로 적용하기 위해, 열기(오른쪽 커서가 오른쪽으로 이동)를 한다. 

 

 

 

커넥션 종료 (3 Hand-Shake)

 

 

 

 

(86) (클라이언트측)

- 클라이언트는 커넥션 종료를 위해 ACK, FIN 플래그와 함께 seqNo(ackNo 14601), ackNo(60441)를 보낸다.

 

(87) (서버측)

- 서버는 클라이언트로 부터 FIN 플래그를 받은 후 

- 서버는 확인 응답을 위해 ACKFIN 플래그와 함께 seqNo(ackNo 60441), ackNo(14602) = seqNo(14601) + 1를 보낸다.

 

(88) (클라이언트측)

- 클라이언트는 서버로 부터 FIN 플래그를 받은 후

- 클라이언트는 확인 응답을 위해  ACK 플래그와 함께 seqNo(ackNo 14602), ackNo(60442) = seqNo(60441) + 1를 보낸다.

- 일정시간 커넥션 종료를 기다린다.

 

(89) (서버측)

- 서버는 클라이언트로 부터 ACK 플래그를 받은 후 커넥션을 종료한다.

 

 

 

 

커넥션 종료 (4 Hand-Shake)

 

 

 

(86) (클라이언트측)

- 클라이언트는 커넥션 종료를 위해 ACKFIN 플래그와 함께 seqNo(ackNo 14601), ackNo(60441)를 보낸다.

 

(87) (서버측)

- 서버는 클라이언트로 부터 FIN 플래그를 받은 후 

- 서버는 확인 응답을 위해 ACK 플래그와 함께 seqNo(ackNo 60441), ackNo(14602) = seqNo(14601) + 1를 보낸다.

 

(88) (클라이언트측)

- 클라이언트는 서버로 부터 ACK 플래그를 받은 후 서버측의 커넥션 종료를 기다린다.

 

(89) (서버측)

- 서버는 클라이언트로 부터 수신할 데이터가 없다고 가정하에

- 서버는 커넥션 종료를 위해 ACKFIN 플래그와 함께 seqNo(ackNo 60441), ackNo(14602) = seqNo(14601) + 1를 보낸다.

 

(90) (클라이언트측)

- 클라이언트는 서버로 부터 ACK, FIN 플래그를 받은 후

- 클라이언트는 확인 응답을 위해  ACK 플래그와 함께 seqNo(ackNo 14602), ackNo(60442) = seqNo(60441) + 1를 보낸다.

- 일정시간 커넥션 종료를 기다린다.

 

(91) (서버측)

- 서버는 클라이언트로 부터 ACK 플래그를 받은 후 커넥션을 종료한다.

 

 

 

커넥션 종료 (Simultaneous)

 

동시 종료라는건 엄밀하게 완전히 같은 시간 동시에 커넥션을 종료 요청을 보냈다는 의미가 아니다.

 

 

(86) (클라이언트측)

- 클라이언트는 커넥션 종료를 위해 ACKFIN 플래그와 함께 seqNo(ackNo 14601), ackNo(60441)를 보낸다.

 

(87) (서버측)

- 서버는 커넥션 종료를 위해 ACKFIN 플래그와 함께 seqNo(ackNo 14601), ackNo(60441)를 보낸다.

 

(88) (서버측)

- 클라이언트의 확인 응답을 기다리는 동안 클라이언트로부터 FIN 플래그를 받으면 이전에 보낸 FIN의 클라이언트의 확인 응답을 받기 위해 CLOSING 상태가 된다.

 

(89) (클라이언트측)

- 서버의 확인 응답을 기다리는 동안 서버로부터 FIN 플래그를 받으면 이전에 보낸 FIN의 서버의 확인 응답을 받기 위해 CLOSING 상태가 된다.

 

(90) (서버측)

- 서버는 확인 응답을 위해  ACK 플래그와 함께 seqNo(ackNo 14601), ackNo(60442) = seqNo(60441) + 1를 보낸다.

 

(91) (클라이언트측)

- 클라이언트는 확인 응답을 위해  ACK 플래그와 함께 seqNo(ackNo 14601), ackNo(60442) = seqNo(60441) + 1를 보낸다.

 

(92) (클라이언트측)

- 클라이언트는 서버로 부터 ACK 플래그를 받은 후

- 일정시간 커넥션 종료를 기다린다.

 

(93) (서버측)

- 서버는 클라이언트로 부터 ACK 플래그를 받은 후

- 일정시간 커넥션 종료를 기다린다.

 

(94) (클라이언트측)

- double MSL(maximum segment life) time이 지나면 커넥션이 닫힌다.

 

(95) (서버측)

- double MSL(maximum segment life) time이 지나면 커넥션이 닫힌다.

 

 

 

결론

 

TCP의 메커니즘에 대한 시나리오를 최대한 정리해보았습니다.

HTTP를 좀 더 깊게 정리하기에 앞서, TCP의 제어 메커니즘들이 얼마나 복잡하고, 고민 많아했는지 더 느낄수 있습니다.

실제로 세그먼트 단위로 RTT로 생각해보면 굉장히 많다고 볼 수 있습니다.

그 만큼 실제로 종단간 통신의 물리적인 거리가 멀 수록 그만큼 레이턴시가 발생할 것은 자명할 정도입니다.

아직 까지 통신의 도구중 빛의 속도보다 빠른 것은 존재하지 않기 때문입니다.

 

이후로 HTTP의 성능최적화를 위해 다시한번 다른 문서로 정리해볼 참입니다.

 

긴 글 읽어주셔서 감사합니다.

 

 

 

 

 

 

참고

 

Behrouz A, Forouzan. 데이터 통신과 네트워크 5판. MCGraw-Hill, 2013

 

http://www.maths.adelaide.edu.au/matthew.roughan/papers/camad2002.pdf

 

http://tcpip.marcolavoie.ca/tcp.html

 

http://www.tcpipguide.com/free/t_TCPConnectionTermination-4.htm

0 Comments
댓글쓰기 폼