TCP 연결의 각 종단에서 호스트들은 연결에 대한 개별 수신 버퍼를 설정합니다.
TCP 연결이 순서대로 올바르게 바이트를 수신할 경우에는 데이터를 수신 버퍼에 저장하는데, 사실 수신하는 애플리케이션이 작업으로 바쁠 수 있고, 이로 인해 오랜 시간 동안 데이터를 읽지 않을 수 있습니다. 애플리케이션이 데이터를 읽는 속도가 비교적 느리다면, 송신자가 점점 더 많은 데이터를 빠르게 전송함으로써 연결의 수신 버퍼에 아주 쉽게 오버플로를 발생 시킵니다.
이처럼 TCP는 송신자가 수신자의 버퍼를 오버플로 시키는 것을 방지하기 위해서 애플리케이션에게 흐름제어 서비스(flow-control service)를 제공합니다.
흐름 제어 와 혼잡제어는 수행하는 동작들이 비슷하지만 명백히 목적이 다르다는 것을 유의하고 진행해 나갑시다.
❗ 흐름제어 목적
수신 측이 송신 측보다 데이터 처리 속도가 느릴 경우 데이터를 손실할 위험이 존재합니다. 흐름 제어는 이런 송신 측과 수신 측의 데이터 처리 속도 차이로 인해 발생하는 문제를 해결하기 위한 기법입니다.
TCP는 송신자가 수신 윈도우(receive window)라는 변수를 유지하여 흐름제어를 제공합니다.
수신 윈도우는 수신 측에서 가용한 버퍼 공간이 얼마나 되는지를 송신자에게 알려 주는 데 사용됩니다.
TCP는 전이중(full-duplex)이므로 각 측의 송신자는 별개의 수신 윈도우를 유지합니다.
우리는 수신 버퍼를 RcvBuffer라고 명명할 것이고, 다음 용어를 살펴봅시다.
TCP는 할당된 버퍼의 오버플로를 허용하지 않으므로 다음 수식이 가능합니다.
rwnd(receive window)로 명명된 수신 윈도우는 버퍼의 여유 공간으로 설정됩니다.
시간에 따라 여유 공간이 변하므로 rwnd는 동적입니다.
모든 세그먼트의 윈도우 필드에 현재의 rwnd값을 설정함으로써 연결 버퍼에 얼마만큼의 여유 공간이 있는지를 송신측에 알려줍니다.
송신측은 명백한 의미를 가지는 두 변수인 LastByteSent와 LastByteAcked를 유지합니다.
이 변수의 차이(LastByteSent - LastByteAcked)는 송신측 호스트가 이 연결에 전송 확인응답 안 된 데이터의 양입니다.
rwnc의 값보다 작은 확인응답 안 된 데이터의 양을 유지함으로써 오버플로가 발생하지 않을 것을 확신합니다.
사실 이 방법에는 사소한 문제가 있다.
예를 들어서, 수신측 버퍼가 현재 rwnd = 0으로 가득 차서 이 내용을 송신측에 전달했다고 가정해 봅시다.
수신측은 버퍼를 비우더라도 송신측에 이 소식을 알리지 않습니다. 즉, 어떠한 세그먼트도 보내지 않습니다.
이러한 문제점으로 인해서 송신 측에서는 rwnd가 0일 때, 1바이트의 데이터로 세그먼트를 계속해서 전송합니다.
UDP의 경우 "흐름제어"를 제공하지 않습니다.
Reference