TCP 세그먼트의 체크섬은 세그먼트의 훼손 여부만 나타낼 뿐이고 체크섬 값이 잘못되었다면 호스트는 해당 패킷을 읽지 않고 폐기합니다. 신뢰성을 보장하기는 부족합니다.
TCP가 신뢰성을 제대로 보장하려면 송신 호스트가 송신한 세그먼트에 문제가 발생했음을 인지할 수 있어야 하고, 세그먼트가 잘못 전송되었음을 알게 되면 해당 세그먼트를 재전송할 수 있어야 합니다.
그래서 가장 먼저 파악해야 할 점이, TCP가 어떤 상황에서 송신한 세그먼트에 문제가 있음을 감지하는지 여부입니다.
수신 호스트 측이 받은 세그먼트의 순서 번호 중에서 일부가 누락되었다면 중복된 ACK 세그먼트를 전송합니다. TCP는 중복된 ACK 세그먼트를 수신했을 때 오류가 생겼음을 감지합니다. 순서 번호 누락이 발생하는 이유는 RTT가 있기 때문입니다.
RTT(Round Trip Time)
메세지를 전송한 뒤 그에 대한 답변을 받는 데까지 걸리는 시간입니다.
TCP 세그먼트를 송신하는 호스트는 모두 재전송 타이머라는 값을 유지합니다. 호스트가 세그먼트를 전송할 때마다 재전송 타이머를 시작하게 되는데, 이 타이머의 카운트다운이 끝난 상황입니다.
타임아웃이 발생할 때까지 ACK 세그먼트를 받지 못하면 세그먼트가 상대 호스트에게 정상적으로 도착하지 않았다고 간주하여 세그먼트를 재전송입니다.
ARQ
수신 호스트의 답변과 타임아웃 발생을 토대로 문제를 진단하고, 문제가 생긴 메시지를 재전송함으로써 신뢰성을 확보하는 방식입니다. Stop-and-wait ARQ와 Go-Back-N ARQ, Selective Repeat ARQ가 존재합니다.
Stop-and-wait ARQ
제대로 전달했음을 확인하기 전까지는 새로운 메세지를 보내지 않는 방식입니다. 메세지를 송신하고, 이에 대한 확인 응답을 받고 다시 메세지를 송신하고 이에 대한 확인 응답을 받는 것을 반복합니다. 단순하지만 신뢰성이 높은 방식입니다. 하지만 이 방식은 네트워크의 이용 효율이 낮아질 수 있다는 단점 존재합니다. 전송되었음을 확인해야만 다음 전송을 시작하는 특성 때문에 송신 호스트 입장에서 확인 응답을 받기 전까지는 다음 전송을 할 수 있어도 불가능합니다.
그래서 수신 호스트 입장에서도 훨씬 더 많은 데이터를 한 번에 전송받을 수 있음에도 불구하고 한 번에 하나씩만 확인 응답을 해야 합니다.
Go-Back-N ARQ는 파이프라이닝 방식을 활용해 여러 세그먼트를 전송하고 도중에 잘못 전송된 세그먼트가 발생한 경우 해당 세그먼트부터 전부 다시 전송하는 방식합니다.
송신 호스트는 여러 세그먼트를 보내고, 수신 호스트는 그에 대한 ACK 세그먼트를 전송합니다. 만약 전송 과정에서 n+2 세그먼트가 유실되었다면 수신 호스트는 그 외 모든 세그먼트를 올바르게 수신했다 하더라도 폐기합니다. 송신 호스트 입장에서는 n+2번 세그먼트에 대한 ACK 세그먼트를 받지 못했기에 타임아웃이 발생하고, 이를 통해 송신 호스트는 잘못된 송신이 있음을 인지합니다. 그래서 ACK 세그먼트를 수신받지 못한 n+2번 세그먼트부터 다시 전송합니다.
Go-Back-N ARQ에서 순서 번호 n번에 대한 ACK 세그먼트는 n번만의 확인 응답이 아니라 n번까지의 확인 응답합니다. 그래서 Go-Back-N ARQ의 ACK 세그먼트를 누적 확인 응답이라고도 합니다.
Selective Repeat ARQ
이름 그대로 선택적으로 재전송하는 방법입니다. Go-Back-N ARQ와 달리 수신 호스트 측에서 제대로 전송받은 각각의 패킷들에 대해 ACK 세그먼트를 보내는 방식입니다. 송신 호스트는 올바르게 수신받지 못한 ACK 세그먼트가 있는지 검사하고, 만일 응답받지 못한 세그먼트가 존재한다면 해당 세그먼트를 재전송합니다.
파이프라이닝 기반의 Go-Back-N ARQ, Selective Repeat ARQ가 정상적으로 동작하려면 반드시 흐름 제어를 고려합니다. 호스트가 한 번에 받아서 처리할 수 있는 세그먼트의 양에는 한계 존재합니다.
수신 버퍼는 수신된 세그먼트가 애플리케이션 프로세스에 의해 읽히기 전에 임시로 저장되는 공간입니다. 버퍼 오버플로는 송신 호스트가 흐름 제어를 고려하지 않고 수신 버퍼의 크기보다 많은 데이터를 전송할 때 버퍼가 넘치게 된 상황을 의미입니다.
흐름 제어는 이런 문제를 방지하고자 송신 호스트가 수신 호스트의 처리 속도를 고려하며 송수신 속도를 균일하게 유지하는 것을 의미합니다. 그래서 오늘날에는 슬라이딩 윈도우를 사용 중입니다. 윈도우는 송신 호스트가 파이프라이닝할 수 있는 최대량을 의미하는데, 윈도우의 크기만큼 확인 응답을 받지 않고
한 번에 전송이 가능하다는 의미입니다. 수신 호스트의 수신 윈도우 크기를 송신 호스트도 알아야 하기 때문에 수신 호스트는 TCP 헤더(윈도우 필드)를 통해 송신 호스트에게 자신이 받아들이고자 하는 데이터의 양을 알립니다.
네트워크에서 혼잡이란 많은 트래픽으로 인해 패킷의 처리 속도가 늦어지거나 유실될 우려가 있는 네트워크 상황을 의미합니다. 따라서 혼잡 제어란 이와 같은 혼잡을 제어하기 위한 기능을 의미합니다.
흐름 제어의 주체가 수신 호스트라면, 혼잡 제어의 주체는 송신 호스트입니다. 송신 호스트는 네트워크 혼잡도를 판단하고 혼잡한 정도에 맞춰 유동적으로 전송량을 조절하며 전송합니다. 혼잡 제어를 이해하기 위해서 혼잡 윈도우도 알아야 합니다.
혼잡 윈도우
혼잡 없이 전송할 수 있을 법한 데이터의 양을 의미합니다. 혼잡 윈도우가 크다면 한 번에 전송할 수 있는 세그먼트 수가 많음을 의미합니다. 반대는 네트워크가 혼잡한 상황이라는 의미이고 한 번에 전송할 수 있는 세그먼트 수가 적음을 의미합니다. 혼잡 윈도우의 크기는 송신 호스트가 혼잡을 방지할 수 있는 세그먼트의 크기를 직접 계산하여 알아내야 합니다. 이를 알아내기 위해 사용하는 방법이 혼잡 제어 알고리즘입니다.
Additive Increase/Muitiplicative Decrease의 약자입니다. '합으로 증가, 곱으로 감소'라는 의미입니다. 혼잡이 감지되지 않으면 혼잡 윈도우를 RTT마다 1씩 선형적으로 증가시키고, 혼잡이 감지되면 혼잡 윈도우를 절반으로 떨어뜨리는 동작을 반복하는 알고리즘입니다.
느린 시작 알고리즘은 혼잡 윈도우를 1부터 시작해 문제없이 수신된 ACK 세그먼트 하나당 1씩 증가시키는 방식입니다. 지수적 증가를 활용해서 초기 전송 속도를 어느 정도 빠르게 확보할 수 있습니다. 그래도 계속 지수적으로 증가시킬 수만은 없기 때문에 느린 시작 임계치라는 값을 설정합니다. 혼잡 윈도우 값이 계속 증가하다가 느린 시작 임계치 이상이 되거나, 타임아웃이 발생하거나 세 번의 중복된 ACK 세그먼트가 발생하여 혼잡이 감지되면 다음 세 가지 방법 중 하나 선택합니다.
타임 아웃 발생
혼잡 윈도우 값을 1로, 느린 시작 임계치를 혼잡이 감지되었을 시점의 혼잡 윈도우 값의 절반으로 초기화한 뒤 느린 시작을 재개합니다.
혼잡 윈도우 >= 느린 시작 임계치
느린 시작 종료, 혼잡 윈도우를 절반으로 초기화하고 혼잡 회피를 수행합니다.
세 번의 중복 ACK 발생
빠른 회복을 수행합니다.
RTT마다 혼잡 위도우를 1MSS씩 증가시키는 알고리즘입니다. 느린 시작 임계치를 넘어선 시점부터는 혼잡이 발생할 가능성이 있으니 조심해서 혼잡 윈도우를 증가시키는 방식입니다.
혼잡 회피 도중 타임아웃이 발생하면 혼잡 윈도우 값은 1로, 느린 시작 임계치는 혼잡이 감지된 시점의 혼잡 윈도우 값의 절반으로 초기화한 뒤 다시 느린 시작을 수행합니다.
세 번의 중복 ACK 세그먼트가 발생되었을 때는 혼잡 윈도우 값과 느린 시작 임계치를 대략 절반으로 떨어뜨린 뒤 빠른 회복 알고리즘을 수행합니다.
빠른 회복 알고리즘은 세 번의 중복 ACK 세그먼트를 수신했을 때 느린 시작은 건너뛰고 혼잡 회피를 수행하는 알고리즘입니다. 이름처럼 빠르게 전송률을 회복하기 위한 알고리즘입니다.
빠른 회복 도중이라도 타임아웃이 발생하면 혼잡 윈도우 크기는 1로, 느린 시작 임계치는 혼잡이 감지된 시점의 절반으로 떨어뜨린 후 다시 느린 시작을 수행합니다.