Transport Layer
전송 계층(Transport Layer)은 OSI 모델의 4계층으로, 네트워크의 한 호스트에서 실행 중인 프로세스와 다른 호스트의 프로세스 간 통신을 담당하는 핵심 계층이다. 이 계층은 종단 간 연결성과 신뢰성 있는 데이터 전송의 기반을 제공한다.
데이터 전송의 관점에서 네트워크 계층 구조는 다양한 수준의 전달 서비스를 제공한다. 데이터 링크 계층은 링크를 통해 두 이웃 노드 간의 프레임 전달을 담당하는 '노드 대 노드 전달(node-to-node delivery)'을 제공한다. 네트워크 계층은 두 호스트 간의 데이터그램 전달을 담당하는 '호스트 대 호스트 전달(host-to-host delivery)'을 제공한다. 전송 계층은 한 단계 더 나아가 '프로세스 대 프로세스 전달(process-to-process delivery)'을 담당하며, 이는 메시지의 일부인 패킷을 한 프로세스에서 다른 프로세스로 전달하는 것을 의미한다.
제시된 이미지는 IP 주소와 포트 번호를 사용한 프로세스 대 프로세스 통신의 핵심 개념을 보여준다. IP 헤더의 IP 주소(193.14.26.7)는 호스트를 선택하며, 전송 계층 헤더의 포트 번호(13)는 해당 호스트에서 실행 중인 특정 프로세스를 선택한다. 이러한 메커니즘을 통해 네트워크의 한 호스트에서 실행 중인 프로세스가 다른 호스트의 특정 프로세스와 통신할 수 있다.
전송 계층에서 가장 일반적인 프로세스 간 통신 방식은 클라이언트/서버 패러다임을 통한 것이다. 클라이언트는 로컬 호스트에서 실행되는 프로세스이며, 서버는 서비스를 제공하기 위해 원격 호스트에서 실행되는 프로세스이다. 통신을 위해서는 로컬 호스트, 로컬 프로세스, 원격 호스트, 원격 프로세스를 정의해야 한다.
주소 지정 측면에서, 데이터 링크 계층의 프레임은 목적지 MAC 주소가 필요하고, 네트워크 계층에서는 IP 주소가 필요하다. 전송 계층에서는 호스트에서 실행 중인 여러 프로세스 중 하나를 선택하기 위한 전송 계층 주소인 포트 번호가 필요하다. 포트 번호의 범위는 0에서 65,535(16비트 정수)까지이다. 잘 알려진 포트 번호(Well-known port number)는 서버를 위한 고정된 범용 포트 번호로, 0에서 1,023까지의 범위를 가진다. 임시 포트 번호(Ephemeral port number)는 클라이언트 호스트에서 실행 중인 전송 계층 소프트웨어에 의해 무작위로 선택된 포트 번호이다.
소켓 주소는 IP 주소와 포트 번호의 조합이다. 전송 계층 프로토콜은 클라이언트 소켓 주소와 서버 소켓 주소의 쌍을 필요로 한다. 이러한 소켓 주소는 Multiplexing(여러 프로세스의 데이터를 하나의 채널로 결합)과 Demultiplexing(수신된 데이터를 적절한 프로세스로 분배) 과정에서 중요한 역할을 한다.
전송 계층은 IP와 같은 신뢰성 없는 네트워크 계층 위에 신뢰성 있는 통신을 구축하는 데 중요한 역할을 하며, TCP와 UDP와 같은 프로토콜을 통해 다양한 응용 프로그램의 요구 사항을 충족시킨다.
Connection
전송 계층에서는 통신 방식에 따라 연결 없는(Connectionless) 서비스와 연결 지향적(Connection-Oriented) 서비스로 구분된다. 이 두 가지 방식은 각각 고유한 특성과 응용 영역을 가지고 있으며, 신뢰성 수준에 따라 다양한 응용 프로그램 요구를 충족시킨다.
연결 없는 서비스는 통신 세션 설정 없이 패킷을 독립적으로 전송하는 방식이다. 이 방식에서 패킷에는 번호가 매겨지지 않으며, 지연되거나 순서가 바뀌어 도착할 수 있다. 또한 확인 응답(acknowledgment) 메커니즘이 없어 패킷의 성공적인 전달을 보장하지 않는다. 인터넷 모델에서 UDP(User Datagram Protocol)는 대표적인 연결 없는 프로토콜이다. UDP는 간단하고 오버헤드가 적어 실시간 응용 프로그램이나 빠른 처리가 필요한 경우에 적합하다.
반면, 연결 지향적 서비스는 통신을 시작하기 전에 먼저 송신자와 수신자 간에 연결을 설정한다. 이후 데이터가 전송되고, 통신이 완료되면 연결이 해제된다. TCP(Transmission Control Protocol)와 SCTP(Stream Control Transmission Protocol)는 인터넷에서 사용되는 대표적인 연결 지향적 프로토콜이다. 이러한 프로토콜은 데이터의 신뢰성 있는 전송을 보장하지만, 연결 설정 및 유지에 따른 오버헤드가 존재한다.
신뢰성 측면에서 전송 서비스는 신뢰성 있는 서비스와 신뢰성 없는 서비스로 구분할 수 있다. 응용 계층 프로그램이 신뢰성을 요구하는 경우, TCP나 SCTP와 같은 신뢰성 있는 전송 프로토콜을 사용한다. 이러한 프로토콜은 데이터의 손실, 중복, 순서 변경 등의 문제를 해결하지만, 상대적으로 속도가 느리고 복잡한 서비스를 제공한다.
반면, 응용 계층 프로그램이 자체적인 흐름 및 오류 제어 메커니즘을 사용하거나, 빠른 서비스가 필요하거나, 또는 서비스의 특성상 흐름 및 오류 제어가 필요하지 않은 경우(예: 실시간 응용 프로그램), UDP와 같은 신뢰성 없는 프로토콜을 사용할 수 있다.
데이터 링크 계층이 신뢰성을 제공하고 흐름 및 오류 제어를 구현하고 있더라도, 전송 계층에서도 신뢰성 제어가 필요할까? 대답은 '예'이다. 인터넷의 네트워크 계층은 신뢰성이 없는(최선형) 전달 방식을 채택하고 있기 때문에, 종단 간 신뢰성을 보장하기 위해서는 전송 계층에서 신뢰성을 구현해야 한다. 네트워크 경로 상의 다양한 링크와 라우터를 통과하면서 패킷이 손실되거나 손상될 가능성이 항상 존재하기 때문이다.
오류 제어는, 특히 연결 지향적 서비스에서, 패킷의 손실, 중복, 손상 등을 감지하고 해결하기 위한 메커니즘을 제공한다. 이는 시퀀스 번호, 확인 응답, 타임아웃, 재전송 등의 기술을 통해 구현된다. 이러한 오류 제어 메커니즘은 네트워크의 불확실성에도 불구하고 신뢰성 있는 데이터 전송을 가능하게 한다.
UDP
사용자 데이터그램 프로토콜(User Datagram Protocol, UDP)은 연결 없는, 신뢰성 없는 전송 프로토콜로 불린다. UDP는 IP가 제공하는 서비스에 호스트 대 호스트 통신 대신 프로세스 대 프로세스 통신을 제공하는 것 외에는 추가적인 기능을 거의 제공하지 않는다. 이처럼 UDP가 제한된 기능을 가지고 있음에도 불구하고, 특정 상황에서는 유용하게 활용될 수 있다.
UDP는 최소한의 오버헤드를 사용하는 매우 단순한 프로토콜이다. 프로세스가 작은 메시지를 보내고 신뢰성에 크게 신경 쓰지 않는 경우, UDP를 사용할 수 있다. 또한 작은 메시지를 보낼 때 TCP를 사용하는 것보다 송신자와 수신자 간의 상호작용이 훨씬 적게 필요하다. 이러한 특성은 실시간 응용 프로그램이나 간단한 질의-응답 모델에 적합하다.
UDP는 여러 잘 알려진 포트 번호를 사용한다. 예를 들어, DNS(포트 53), DHCP 클라이언트(포트 68), DHCP 서버(포트 67), SNMP(포트 161), NTP(포트 123) 등이 UDP를 사용하는 대표적인 서비스이다.
UDP 프레임 형식은 비교적 단순하다. UDP 헤더는 소스 포트 번호(16비트), 목적지 포트 번호(16비트), 길이(16비트), 체크섬(16비트)의 네 가지 필드로 구성되어 있다. 이러한 간결한 구조는 UDP의 가벼운 특성을 반영한다.
UDP 프로토콜의 주요 특징과 작동 방식은 다음과 같다:
연결 없는 서비스: UDP는 연결 없는 서비스를 제공하여 각 데이터그램은 독립적으로 처리된다. 이는 통신 세션 설정 없이도 데이터를 전송할 수 있음을 의미한다.
흐름 및 오류 제어: UDP에는 흐름 제어가 없으므로 윈도우 메커니즘이 존재하지 않는다. 또한 체크섬을 제외하고는 오류 제어 메커니즘도 없다. 이는 데이터의 신뢰성보다 전송 속도를 우선시하는 설계 철학을 반영한다.
캡슐화 및 역캡슐화: UDP 프로토콜은 메시지를 IP 데이터그램으로 캡슐화하고 역캡슐화한다. 이 과정에서 UDP 헤더가 추가되어 프로세스 간 통신을 가능하게 한다.
UDP의 큐잉(Queuing) 메커니즘은 클라이언트와 서버 측에서 다음과 같이 작동한다:
클라이언트 측 큐잉: 프로세스가 시작될 때, 운영 체제에 포트 번호를 요청한다. 클라이언트 프로세스는 요청에 지정된 소스 포트 번호를 사용하여 메시지를 송신 큐에 전송한다. UDP는 메시지를 하나씩 제거하고, UDP 헤더를 추가한 후 IP로 전달한다. 송신 큐가 넘칠 수 있으며, 이 경우 운영 체제는 클라이언트 프로세스에 더 이상 메시지를 보내기 전에 대기하도록 요청할 수 있다. 메시지가 클라이언트에 도착하면, UDP는 사용자 데이터그램의 목적지 포트 번호 필드에 지정된 포트 번호에 대한 수신 큐가 생성되었는지 확인한다. 큐가 있으면 UDP는 수신된 사용자 데이터그램을 큐의 끝으로 보낸다.
서버 측 큐잉: 서버가 실행을 시작할 때, 잘 알려진 포트를 사용하여 수신 및 송신 큐를 요청한다. 메시지가 서버에 도착하면, UDP는 사용자 데이터그램의 목적지 포트 번호 필드에 지정된 포트 번호에 대한 수신 큐가 생성되었는지 확인한다. 큐가 있으면 UDP는 수신된 사용자 데이터그램을 큐의 끝으로 보낸다. 서버가 클라이언트에 응답하려는 경우, 요청에 지정된 소스 포트 번호를 사용하여 메시지를 송신 큐로 보낸다. UDP는 메시지를 하나씩 제거하고, UDP 헤더를 추가한 후 IP로 전달한다.
UDP의 주요 응용 분야는 다음과 같다:
UDP는 흐름 및 오류 제어에 대한 우려가 적은 단순한 요청-응답 통신이 필요한 프로세스에 적합하다. 그러나 FTP와 같은 대량 데이터 전송에는 사용되지 않는다. 내부 흐름 및 오류 제어를 포함하는 TFTP(Trivial File Transfer Protocol)에는 적합하다. 또한 멀티캐스팅을 위한 적합한 전송 프로토콜이며, RIP(Routing Information Protocol)와 같은 일부 경로 업데이트 프로토콜에 사용된다. 또한 SNMP(Simple Network Management Protocol)와 같은 관리 프로세스에도 사용된다.
이러한 특성으로 인해 UDP는 지연 시간에 민감한 실시간 응용 프로그램, 간단한 질의-응답 서비스, 그리고 멀티캐스트 통신에 널리 사용되고 있다.
TCP
전송 제어 프로토콜(Transmission Control Protocol, TCP)은 연결 지향적 프로토콜로, 데이터를 전송하기 위해 두 TCP 간에 가상 연결을 생성한다. 또한 TCP는 전송 계층에서 흐름 제어와 오류 제어 메커니즘을 사용하여 신뢰성 있는 통신을 보장한다.
TCP는 스트림 지향적 프로토콜이다. TCP는 두 프로세스가 인터넷을 통해 데이터를 전달하는 가상의 '관(tube)'으로 연결된 환경을 생성한다. 이 스트림 전달 서비스는 응용 프로그램이 데이터를 연속적인 바이트 스트림으로 간주할 수 있게 해준다.

송신 및 수신 프로세스가 동일한 속도로 데이터를 생성하고 소비하지 않을 수 있기 때문에, TCP는 저장을 위한 버퍼가 필요하다. 이를 구현하는 한 가지 방법은 원형 배열(circular array)을 사용하는 것이다. 이 버퍼는 송신자와 수신자 간의 속도 차이를 완화하는 데 도움이 된다.
전송 계층에서 TCP는 여러 바이트를 세그먼트(segment)라고 불리는 패킷으로 그룹화한다. TCP는 제어 목적으로 각 세그먼트에 헤더를 추가하고 전송을 위해 IP 계층에 세그먼트를 전달한다. 세그먼트는 IP 데이터그램으로 캡슐화되어 전송된다. 이 전체 작업은 수신 프로세스에게 투명하게 이루어진다. 순서가 맞지 않게 수신되거나, 손실되거나, 손상된 세그먼트는 재전송될 수 있다.
TCP는 전이중(full-duplex) 서비스를 제공한다. 두 응용 프로그램이 서로 연결된 후에는 둘 다 데이터를 송신하고 수신할 수 있다. 피기백킹(piggybacking)은 A에서 B로 패킷이 이동할 때, B로부터 받은 패킷의 확인 응답도 함께 전달할 수 있는 기능이다.
TCP의 연결 지향적 서비스는 다음 단계로 이루어진다:
- A의 TCP가 B의 TCP에게 알리고 B의 TCP로부터 승인을 받는다.
- A의 TCP와 B의 TCP는 양방향으로 데이터를 교환한다.
- 두 프로세스 모두 전송할 데이터가 없고 버퍼가 비어 있으면, 두 TCP는 버퍼를 해제한다.
TCP는 신뢰성 있는 서비스를 제공하기 위해 확인 응답 메커니즘을 사용하여 데이터의 안전하고 정확한 도착을 확인한다.
TCP에서는 세그먼트 번호 값을 위한 필드가 없다. 대신 시퀀스 번호(sequence number)와 확인 응답 번호(acknowledgment number)라는 두 필드가 있다. 이 두 필드는 바이트 번호를 참조한다. 각 연결에서 전송되는 모든 데이터 바이트는 TCP에 의해 번호가 매겨진다. 번호 매기기는 무작위로 생성된 번호부터 시작한다. 첫 번째 바이트의 번호 범위는 0에서 2^32-1이다(예: 무작위 번호가 1,057이고 총 바이트 수가 6,000인 경우, 바이트는 1,057에서 7,056까지 번호가 매겨진다). 바이트 번호 매기기는 흐름 제어와 오류 제어에 사용된다.
바이트에 번호가 매겨진 후, TCP는 전송되는 각 세그먼트에 시퀀스 번호를 할당한다. 각 세그먼트의 시퀀스 번호는 해당 세그먼트에 포함된 첫 번째 바이트의 번호이다.
세그먼트의 확인 응답 필드 값은 상대방이 다음에 받을 것으로 예상하는 바이트의 번호를 정의한다. 확인 응답 번호는 누적된다. 이는 수신자가 모든 바이트를 올바른 순서로 수신했음을 의미한다.
TCP(전송 제어 프로토콜)는 세그먼트라는 데이터 단위를 사용하며, 이 세그먼트는 헤더와 데이터로 구성된다. TCP 세그먼트 형식에는 원활한 통신을 위한 다양한 필드가 포함되어 있다.
TCP 헤더의 제어 필드는 TCP의 핵심 기능인 흐름 제어, 연결 설정 및 종료, 데이터 전송 모드를 가능하게 한다. 이 필드에는 URG(긴급), ACK(확인 응답), PSH(푸시), RST(리셋), SYN(동기화), FIN(종료) 등의 제어 비트가 포함되어 있으며, 각각 특정 기능을 수행한다.
TCP Connection
TCP는 연결 지향적 프로토콜로, 소스와 목적지 간에 가상 경로를 설정한다. 한 메시지에 속하는 모든 세그먼트는 이 가상 경로를 통해 전송된다. 단일 가상 경로를 사용하면 확인 응답 과정과 손상되거나 손실된 프레임의 재전송이 용이해진다.
TCP가 연결 없는 프로토콜인 IP의 서비스를 사용하면서 어떻게 연결 지향적일 수 있는지 의문이 들 수 있다. 중요한 점은 TCP 연결이 물리적이 아닌 가상적이라는 것이다. TCP는 개별 세그먼트를 수신자에게 전달하기 위해 IP의 서비스를 사용하지만, 연결 자체는 TCP가 제어한다.

TCP는 전이중(full-duplex) 모드로 데이터를 전송한다. 두 기기의 TCP가 연결되면 동시에 서로에게 세그먼트를 보낼 수 있다. 이는 데이터가 전송되기 전에 각 당사자가 통신을 초기화하고 상대방으로부터 승인을 받아야 함을 의미한다.
동시 개방(Simultaneous Open)은 두 프로세스가 모두 능동 개방(active open)을 실행할 때 발생할 수 있다. 이 경우 두 TCP는 서로에게 SYN+ACK 세그먼트를 전송하고, 하나의 단일 연결이 설정된다.
SYN 플러딩 공격(SYN Flooding Attack)은 악의적인 공격자가 데이터그램의 소스 IP 주소를 위조하여 각각 다른 클라이언트에서 오는 것처럼 위장하여 서버에 많은 수의 SYN 세그먼트를 보낼 때 발생한다. SYN 플러딩 공격은 서비스 거부 공격(denial-of-service attack)이라는 보안 공격의 일종으로, 공격자가 시스템을 많은 서비스 요청으로 독점하여 시스템이 붕괴되고 모든 요청에 대한 서비스를 거부하게 된다.
데이터 전송 중에는 푸시 작업(Push Operation)과 긴급 데이터(Urgent Data) 기능이 있다. 푸시 작업은 전송 사이트의 응용 프로그램이 송신 TCP에게 윈도우가 채워질 때까지 기다리지 않고 즉시 세그먼트를 생성하여 전송하도록 요청하는 것이다. 긴급 데이터는 송신 응용 프로그램이 수신 응용 프로그램에 의해 데이터 조각이 순서와 상관없이 읽혀지기를 원할 때 사용된다. 송신자는 URG 비트가 설정된 세그먼트를 보낼 수 있으며, 수신 TCP는 URG 비트가 설정된 세그먼트를 받으면 포인터 값을 사용하여 긴급 데이터를 세그먼트에서 추출하고 이를 순서와 상관없이 수신 응용 프로그램에 전달한다.

연결 종료(Connection Termination)는 TCP 연결을 종료하는 프로세스이다. 일반적으로 양방향 통신이 완료되면 연결은 해제된다. 이는 주로 FIN 비트를 사용하여 이루어진다.

반 종료(Half Close)는 TCP의 특별한 기능으로, 한 방향의 데이터 흐름은 종료하지만 다른 방향은 계속 활성 상태로 유지할 수 있다. 이는 한 쪽이 더 이상 데이터를 보낼 것이 없지만 상대방으로부터 데이터를 계속 받기를 원할 때 유용하다.
TCP Flow Control

위 그림은 TCP의 기본적인 흐름 제어 메커니즘을 보여준다. 클라이언트와 서버 간의 통신에서 윈도우 크기(Window Size)를 사용하여 데이터 전송 속도를 조절하는 과정이 단계별로 나타나 있다.
- 연결 설정 단계에서 클라이언트와 서버는 각각 자신의 윈도우 크기(800 바이트)를 설정한다.
- 클라이언트는 200 바이트의 데이터를 전송하고, 윈도우 크기는 600 바이트로 감소한다.
- 서버는 데이터를 수신하고 확인 응답(ACK)을 보낸다.
- 클라이언트가 추가로 300 바이트를 전송하면, 윈도우 크기는 400 바이트로 감소한다.
- 서버 측에서 데이터가 소비되면 윈도우가 다시 열려, 추가 데이터 수신이 가능해진다.
이 과정은 송신자가 수신자의 처리 능력을 초과하는 데이터를 전송하지 않도록 하여, 네트워크 혼잡과 버퍼 오버플로우를 방지한다.
위 그림은 TCP의 지연된 확인 응답 메커니즘을 보여준다. 이 기술은 네트워크 오버헤드를 줄이기 위해 여러 데이터 패킷에 대해 단일 확인 응답을 보내는 방식이다.
- 서버로부터 데이터가 도착하면 클라이언트는 ACK 타이머를 시작한다.
- 타이머가 만료되기 전에 추가 데이터가 도착하면, 클라이언트는 이전 데이터와 새 데이터에 대해 하나의 ACK를 보낸다.
- 이 방식은 네트워크 트래픽을 줄이는 데 효과적이지만, 타이머 설정이 중요하다.
위 그림은 세그먼트 손실 시 TCP의 대응 방식을 보여준다:
- 클라이언트가 여러 세그먼트를 연속해서 보내는 도중 일부 세그먼트가 손실된다.
- 서버는 수신한 마지막 순서 번호까지의 확인 응답을 보낸다.
- 클라이언트는 타임아웃이 발생하면 손실된 세그먼트부터 재전송을 시작한다.
위 그림은 중복 ACK에 기반한 빠른 재전송 메커니즘을 보여준다:
- 클라이언트가 연속된 세그먼트를 전송하는 도중 일부가 손실된다.
- 서버는 손실 이전까지 수신한 데이터에 대해 동일한 ACK를 반복적으로 보낸다.
- 클라이언트가 동일한 ACK를 여러 번 수신하면, 타임아웃을 기다리지 않고 손실된 세그먼트를 즉시 재전송한다.
위 그림은 확인 응답이 손실된 경우의 처리 방식을 보여준다:
- 클라이언트가 세그먼트를 전송하고 서버가 확인 응답을 보내지만, 이 확인 응답이 네트워크에서 손실된다.
- 클라이언트는 타임아웃 후 해당 세그먼트를 재전송한다.
- 서버는 이미 처리한 세그먼트를 다시 받더라도, 적절한 확인 응답을 보낸다.
이때 서버가 이 중복된 세그먼트를 받게 되면, 서버는 이 세그먼트가 중복임을 인식하고 클라이언트가 확인 응답을 받지 못했다는 것을 이해하여 다시 Ack: 701을 보낸다.
이러한 메커니즘들을 통해 TCP는 패킷 손실, 순서 변경, 네트워크 혼잡 등의 문제에도 불구하고 신뢰성 있는 데이터 전송을 보장할 수 있다.
TCP Congestion Control
TCP(전송 제어 프로토콜)의 혼잡 제어(Congestion Control)는 네트워크의 과부하를 방지하고 효율적인 데이터 전송을 보장하기 위한 핵심 메커니즘이다. 이미지는 TCP 혼잡 제어의 두 가지 주요 구현 방식인 TCP Tahoe와 TCP Reno의 동작을 시각적으로 보여준다.
혼잡 제어는 송신자의 혼잡 윈도우(congestion window, cwnd)를 조절하여 네트워크 상태에 따라 데이터 전송 속도를 동적으로 관리한다. 혼잡 윈도우는 수신자의 확인 응답(ACK) 없이 네트워크에 전송할 수 있는 데이터의 최대량을 결정한다.
TCP 혼잡 제어는 슬로우 스타트(Slow Start)와 혼잡 회피(Congestion Avoidance) 라는 두 개의 단계로 구성된다.
슬로우 스타트 단계에서는 연결 시작 시 또는 혼잡 발생 후 cwnd를 작은 값(일반적으로 1 MSS)에서 시작하여 매 RTT(Round Trip Time)마다 지수적으로(exponentially) 증가시킨다. 즉, 확인 응답을 잘 받을 때마다 cwnd를 두 배로 늘려 전송량을 빠르게 증가시킨다. 이는 네트워크 용량을 신속하게 탐색하기 위한 방법이다.
cwnd가 특정 임계값(ssthresh, slow start threshold)에 도달하면, TCP는 혼잡 회피 단계로 전환한다. 이 단계에서는 cwnd를 더 조심스럽게, 매 RTT마다 1 MSS씩 선형적으로(additively) 증가시킨다. 이 접근 방식은 "가산 증가, 승산 감소"(Additive Increase, Multiplicative Decrease, AIMD) 원칙을 따른다.
네트워크 혼잡이 감지되면, TCP는 혼잡 윈도우를 크게 감소시켜 네트워크 부하를 줄인다. 혼잡 감지는 타임아웃(Time-out) 발생 또는 중복 ACK(3 duplicate ACKs) 수신을 통해 이루어진다.
위 그림은 TCP Tahoe의 동작을 보여준다. TCP Tahoe에서는 혼잡이 감지되면(타임아웃이나 3개의 중복 ACK), cwnd를 1 MSS로 재설정하고 ssthresh를 혼잡 발생 시점의 cwnd의 절반으로 설정한 후 슬로우 스타트를 다시 시작한다. cwnd가 새로운 ssthresh에 도달하면 혼잡 회피 단계로 전환된다.
위 그림은 TCP Reno의 동작을 보여준다. TCP Reno는 Tahoe의 개선 버전으로, 혼잡 감지 방식에 따라 다르게 반응한다. 타임아웃이 발생하면 Tahoe와 동일하게 동작하지만, 3개의 중복 ACK를 받으면 "빠른 복구"(Fast Recovery) 메커니즘을 사용한다. 이 경우 cwnd를 절반으로 줄이고 바로 혼잡 회피 단계로 진입한다. 이는 네트워크에 일부 패킷 손실은 있지만 완전한 혼잡 상태는 아니라고 가정하기 때문이다.
TCP 혼잡 제어의 중요한 특성 중 하나는 초기 연결 설정 시 항상 느린 속도로 시작한다는 점이다. 이로 인해 TCP 서비스는 초반에 반드시 느리게 시작된다. 이 문제를 해결하기 위해 여러 TCP 연결을 동시에 사용하여 통계적 다중화(statistical multiplexing)를 통해 전체 전송 속도를 향상시키는 방법이 사용된다.