-
TCP의 흐름제어, 오류제어Computer Science/Network 2020. 10. 3. 18:44
송신자의 데이터 전송 속도가 수신자의 데이터 처리 속도보다 느릴 경우에는 심각한 문제가 발생하지 않는다.
그러나 송신자의 데이터 전송 속도가 수신자의 데이터 처리 속도보다 빠를 경우에는 심각한 문제가 발생할 수 있다.
수신자가 데이터를 아직 처리하지 못했는데, 송신자는 계속해서 데이터를 전송한다.
물론 이런 경우를 대비해 수신자는 버퍼를 마련해서 데이터를 차곡차곡 저장한다.
그런데 만약 이 큐를 꽉 채우고도 남을 정도로 송신자가 데이터를 전송한다면 어떨까?
그러면 그냥 그대로 데이터를 잃어버리는 것이다.그래서 우리는 데이터 손실을 없애야 한다 => 이를 위해 수신자가 자신의 상태를 송신자에게 알린다.
흐름제어 : 송신측과 수신측의 데이터 처리 속도 차이를 해결하기 위한 기법
혼잡제어 : 송신측의 데이터 전달과 네트워크의 데이터 처리 속도 차이를 해결하기 위한 기법
흐름제어 - Stop and Wait , Sliding Window오류제어 - Stop and Wait , Go Back N , Selective Repeat
혼잡제어
- AIMD(Additive Increase / Multicative Decrease),
- Slow Start,
- Fast Retransmit(빠른 재전송),
- Fast Recovery(빠른 회복)
흐름제어
(1) Stop and Wait
- 이름 그대로 송신측에서 데이터를 보내고 수신측의 응답을 받고 그 다음의 데이터를 보내줌
단 1개의 패킷을 단위로 함
비효율적
(2) Sliding Window
- 아마 여러개의 패킷을 가능케하는 기법이 핵심
슬라이딩 윈도는 아직 확인을 받지 않고도 여러 패킷을 보내는 것을 가능케 하기 때문에, 매번 전송한 패킷에 대해 확인을 받아야만 그 다음 패킷을 전송하는 방법(stop-and-wait)을 사용하는 것보다 훨씬 네트워크를 효율적으로 사용할 수 있다.
첫 윈도우 크기는 3-hand-shaking 때 결정
수신측 버퍼의 여유용량을 기준으로
윈도우 사이즈는 여러 요인에 의해 결정. 대표적인 값 RTT (RTT(Round Trip Time) - 패킷의 왕복시간)
윈도우 사이즈는 수신측 버퍼의 여유용량의 1/10이 되기도 함
-상세 과정
일단 전송되는 패킷들에겐 일련번호(sequence number)가 매겨지게 된다. 가령 전송하고자하는 n개의 패킷이 있다고 하면 [1, 2, ..., n]와 같이 일련번호를 매길 수 있다.
송신자(sender)는 다음의 세 가지 변수를 관리한다.
- SWS (send window size) - 윈도 크기
- LAR (last acknowledgement received) - 마지막으로 확인받은 패킷의 번호
- LFS (last frame sent) - 마지막으로 보낸 패킷의 번호
그렇다면 송신자의 윈도는 [(LAR+1), ... , (LAR+SWS)]가 된다. 송신자는 이 윈도에 포함되는 모든 패킷들을 전송하고, 수신자로부터 ACK가 올때까지 기다린다. LFS는 LAR+SWS가 된다. 아무 문제가 없었다면 수신자로부터 LAR+1의 ACK를 가장 먼저 받게 된다. 그렇다면 송신자는 LAR을 갱신하고, 그렇게되면 LAR+SWS도 그만큼 증가하기 때문에 그 다음 패킷을 보낼 수 있게 된다.
또 만약 어느 패킷에 대해 ACK를 받지 못한 경우, 송신자는 일정시간을 기다린 후, 확인받지 못한 패킷을 재전송한다. 이미 현재의 윈도에 해당되는 패킷을 모두 보냈는데 ACK를 받지 못해 윈도를 이동시키지 못하고 있다면 필요한 ACK가 오기까지 기다려야 한다.
수신자(receiver)도 윈도를 따로 운용한다. 수신자는 다음의 세 가지 변수를 관리한다.
- RWS (receive window size) - 윈도 크기
- LAF (last acceptable frame) - 수신할 수 있는 마지막의 패킷의 번호
- LFR (last frame received) - 마지막으로 수신한 패킷의 번호
송신자와 비슷하게 수신자도 LAF와 LFR을 갱신하여 윈도를 이동시키며 패킷들을 접수한다. 받는 패킷들에 대한 ACK를 보내주는 것이 수신자의 역할이다. 수신자가 보내는 ACK는 마지막으로 도착한 패킷에 대한 ACK가 아니고, 연속적으로 도착한 패킷중의 가장 마지막 패킷에 대한 ACK이다. 예를 들어 1, 2, 3, 4, 6, 7의 패킷이 순서대로 도착하였다면, 수신자는 그 7번의 패킷을 받아 버퍼에 저장하고, 4번의 패킷에 대한 ACK를 송신자에게 보낸다. 만약 그 다음에 도착하는 패킷이 5번이라면, 수신자는 그제서야 7번의 패킷에 대한 ACK를 송신자에게 보내게 된다.
만약 윈도에 포함되지 않는 패킷이 도착하면, 수신자는 단순히 이 패킷을 버린다.
결론적으로 데이터의 전송이 되는 동안 아래의 두 가지 부등식이 항상 성립하여야한다.
- LFS-LAR <= SWS
- LAF-LFR <= RWS
네트워크의 상황에 따라 송신자나 수신자는 각자의 윈도 크기(SWS, RWS)를 조절할 수도 있다.
[출처 ko.wikipedia.org/wiki/%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%94%A9_%EC%9C%88%EB%8F%84]
오류제어
오류가 발생했다는 것을 어떻게?
크게 2가지
1. 타임아웃인 경우.
송신 측은 데이터를 전송했는데 수신 측이 응답하지 않고 일정 시간이 경과한 경우이다.
이때, 수신측이 NACK(부정응답)을 보내거나 송신측에게 ACK(긍정응답)이 오지 않거나로 판별.
NACK 추가적인 로직이 필요하기 때문에
일반적으로 ACK로만 사용해서 오류를 추정하는 방법 사용.
2, 송신측이 중복된 ACK를 받는 경우.
출처 evan-moon.github.io/2019/11/22/tcp-flow-control-error-control/#sliding-window 송신측에서 ACK2를 받고 SEQ2를 보냈는데 이 데이터가 유실되고
SEQ3을 받은 수신측이 다시 ACK2를 보내는 경우
송신측은 SEQ2가 유실되었다고 판단할 수 있다.
단, 패킷 기반 전송을 하는 TCP의 특성 상 각 패킷의 도착 순서가 무조건 보장되는 것이 아니기 때문에 위 예시처럼 중복된 ACK를 한 두번 받았다고 해서 바로 에러라고 판별하지는 않고, 보통 3회 정도 받았을 때 에러라고 판별하게 된다.
오류 제어 기법
(1) Stop and Wait
- 흐름제어도 되면서 오류제어도 되는 방식이다.
출처 evan-moon.github.io/2019/11/22/tcp-flow-control-error-control/#sliding-window (2) Go Back N
송신측이 1,2,3,4,5,6,7을 보내고
수신측이 1,2,3,4,6,7을 받으면
수신측이 5번 이후의 데이터는 폐기하고 NACK를 수신측에게 보낸다.
그럼 송신측이 5번으로 되돌아가서 다시 전송한다.
(3) Selective Repeat
Go Back N 과 비슷하지만
수신측이 1,2,3,4,6,7을 받고
5번으로 되돌아가서 다시 전송하지 않고
5번만 다시 보낸다. 이에 ACK를 받으면
8번부터 보낸다.
이 방식을 사용하는 수신 측의 버퍼에 쌓인 데이터가 연속적이지 않다는 단점이 존재한다.
수신측은 5번 데이터를 1,2,3,4,6,7의 중간에 끼워넣어야 정렬해야 한다.
이때 같은 버퍼 안에서 데이터를 정렬할 수는 없으니, 별도의 버퍼가 필요하게 된다.
결국 재전송이라는 과정이 빠진 대신 재정렬이라는 과정이 추가된 것인데, 이 둘 중에 재전송이 좀 더 이득인 상황에서는 Go Bank N 방식을, 재정렬이 좀 더 이득인 상황에서는 Selective Repeat 방식을 사용하면된다.
(아무래도 대부분의 경우에는 정글이나 다름 없는 네트워크를 다시 사용하는 쪽보다는 그냥 수신 측이 재정렬을 하는 것이 이득인 경우가 많다보니 기본적으로 Selective Repeat을 사용하는 것이 아닌가싶다라는 의견이 있네요)
만약 TCP 통신에서 Selective Repeat 방식을 사용하고 싶다면, TCP의 옵션 중 SACK 옵션을 1로 설정하면 된다…만 사실 기본적으로 켜져 있는 경우가 많다.
$ sysctl net.inet.tcp | grep sack: net.inet.tcp.sack: 1
OSX 같은 경우, sysctl 명령어를 사용하여 TCP와 관련된 커널 변수들을 확인해보면 그 중 net.inet.tcp.sack 값이 1로 잡혀있는 것을 확인할 수 있다.
아무래도 대부분의 경우에는 정글이나 다름 없는 네트워크를 다시 사용하는 쪽보다는 그냥 수신 측이 재정렬을 하는 것이 이득인 경우가 많다보니 기본적으로 Selective Repeat을 사용하는 것이 아닌가싶다.
참고 및 출처
ko.wikipedia.org/wiki/%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%94%A9_%EC%9C%88%EB%8F%84
evan-moon.github.io/2019/11/22/tcp-flow-control-error-control/#sliding-window
패킷의 흐름과 오류를 제어하는 TCP
은 원활한 통신을 위해 전송하는 데이터 흐름을 제어하고 네트워크의 혼잡 상태를 파악해서 대처하는 기능을 프로토콜 자체에 포함하고 있다.
evan-moon.github.io
'Computer Science > Network' 카테고리의 다른 글
TCP Keepalive 와 HTTP Keepalive (0) 2024.02.10 TCP 소켓 옵션 (0) 2023.01.28 TCP의 혼잡제어 (0) 2020.10.06 로드밸런서(Load Balancer)란?? (0) 2020.09.30