- 0
- 113 words
TCP를 처음 공부할 때 가장 많이 듣는 말 중 하나가 있다.
바로 TCP는 신뢰성 있는 데이터 전송을 지원한다는 것이다.
그런데 여기서 조금 궁금해진다.
도대체 TCP는 어떻게 데이터를 안전하게 전달하는 걸까?
인터넷을 통해 데이터를 보내면 중간에 패킷이 사라질 수도 있고, 예상보다 늦게 도착할 수도 있다. 심지어 먼저 보낸 데이터보다 나중에 보낸 데이터가 먼저 도착하는 경우도 생길 수 있다.
TCP는 이런 상황을 어느 정도 고려해서 데이터를 관리한다.
대표적으로 시퀀스 번호, ACK, 재전송, 체크섬, 윈도우 제어 같은 기능을 사용한다.
데이터를 그냥 보내지는 않는다
TCP에서 데이터를 보낼 때는 각각의 데이터 흐름을 관리하기 위한 번호가 사용된다.
이것이 **시퀀스 번호(Sequence Number)**다.
예를 들어 다음과 같은 데이터가 있다고 해보자.
A B C D E F G H
TCP에서는 이 데이터를 그냥 한 덩어리로 보내는 것이 아니라 전송 과정에서 여러 세그먼트로 나누어 전달할 수 있다.
개념적으로 보면:
Segment 1 → A B
Segment 2 → C D
Segment 3 → E F
Segment 4 → G H
각 데이터에는 순서를 확인할 수 있는 정보가 들어간다.
그래서 수신 측에서는 데이터를 받은 뒤 원래 순서대로 정리할 수 있다.
시퀀스 번호가 중요한 이유
인터넷에서는 데이터가 항상 보낸 순서대로 도착한다고 보장할 수 없다.
예를 들어:
보낸 순서
1 → 2 → 3 → 4
도착한 순서
1 → 3 → 2 → 4
이런 일이 발생할 수도 있다.
TCP는 시퀀스 번호를 이용해서 어떤 데이터가 먼저 왔는지 확인한다.
따라서 3번이 먼저 도착했다고 해서 바로 애플리케이션에 순서대로 전달하는 것이 아니라, 필요한 경우 데이터를 정리해서 올바른 순서로 처리한다.
이 부분이 TCP가 순서가 보장되는 바이트 스트림을 제공하는 중요한 이유다.
ACK로 데이터를 확인한다
TCP에서 또 중요한 것이 **ACK(Acknowledgment)**다.
ACK는 쉽게 말하면 상대방에게 데이터를 정상적으로 받았다는 것을 알려주는 응답이다.
예를 들어:
Client ───── 데이터 ─────→ Server
Client ←──── ACK ─────── Server
서버가 데이터를 정상적으로 받았다면 ACK를 보내서 수신 상황을 알려줄 수 있다.
이런 확인 과정이 있기 때문에 송신 측에서는 데이터가 어디까지 정상적으로 전달됐는지를 판단할 수 있다.
데이터가 사라지면 어떻게 할까?
네트워크에서는 패킷 손실이 발생할 수 있다.
예를 들어:
Client
1 ─────────────→ Server
2 ─────────────→ Server
3 ───── X
4 ─────────────→ Server
3번 데이터가 중간에서 사라졌다고 해보자.
TCP에서는 수신 측에서 데이터가 제대로 들어오지 않았다는 사실을 송신 측이 알아차릴 수 있도록 ACK와 시퀀스 번호 등을 이용한다.
그리고 송신 측은 필요한 데이터를 다시 보내는 **재전송(Retransmission)**을 수행한다.
1 → 정상 수신
2 → 정상 수신
3 → 손실
4 → 수신
3 → 다시 전송
이런 방식으로 데이터 손실에 대응한다.
물론 TCP가 네트워크에서 발생하는 모든 문제를 해결해준다는 의미는 아니다.
연결 자체가 끊어지거나 상대방이 응답하지 않는 상황이라면 결국 통신이 실패할 수도 있다.
TCP가 제공하는 것은 전송 과정에서 발생할 수 있는 손실이나 순서 문제 등을 감지하고 처리하는 신뢰성 있는 전송 기능이라고 보는 게 정확하다.
ACK가 하나씩만 필요한 것은 아니다
여기서 TCP가 데이터를 보낼 때 매번 하나 보내고 ACK를 기다린 다음 다시 하나 보내는 방식이라고 생각할 수도 있다.
그렇게 하면 너무 느려진다.
실제 TCP는 여러 데이터를 한꺼번에 전송하면서 ACK를 받을 수 있도록 동작한다.
예를 들어:
1 → 2 → 3 → 4 → 5
↓
여러 데이터 전송
이런 식으로 여러 세그먼트를 전송하면서 네트워크 상황에 맞춰 전송량을 조절한다.
여기에서 등장하는 개념이 **윈도우(Window)**다.
TCP 윈도우란?
TCP에서는 송신자가 상대방이 처리할 수 있는 것보다 지나치게 많은 데이터를 보내지 않도록 조절한다.
수신 측은 자신이 현재 어느 정도의 데이터를 받을 수 있는지 알려줄 수 있다.
이것을 **수신 윈도우(Receive Window)**라고 한다.
예를 들어 수신 측에서:
현재 받을 수 있는 데이터 = 10KB
라고 알려주면 송신 측은 이를 고려해서 데이터를 전송한다.
수신 버퍼가 부족한데 계속 데이터를 밀어 넣으면 문제가 생길 수 있기 때문이다.
그래서 TCP는 데이터의 신뢰성뿐만 아니라 **흐름 제어(Flow Control)**도 수행한다.
네트워크가 혼잡하면 어떻게 할까?
TCP가 고려하는 것은 수신자의 처리 능력만이 아니다.
인터넷에는 수많은 장비와 사용자가 연결되어 있기 때문에 특정 구간에 데이터가 몰릴 수도 있다.
이런 상황을 **네트워크 혼잡(Congestion)**이라고 한다.
TCP는 네트워크 상황을 고려하면서 전송량을 조절하는 **혼잡 제어(Congestion Control)**도 사용한다.
쉽게 보면:
네트워크 여유 있음
→ 전송량 증가
네트워크 혼잡
→ 전송량 감소
이런 방향으로 동작한다고 생각할 수 있다.
실제 TCP에는 Slow Start, Congestion Avoidance, Fast Retransmit 같은 여러 알고리즘이 사용된다.
여기까지 들어가면 TCP가 단순히 데이터를 보내고 ACK만 확인하는 프로토콜은 아니라는 것을 알 수 있다.
체크섬으로 데이터 오류도 확인한다
TCP에는 **체크섬(Checksum)**도 포함되어 있다.
네트워크를 통해 데이터가 전달되는 과정에서 데이터가 손상될 가능성이 있기 때문이다.
수신 측에서는 체크섬을 확인해서 TCP 세그먼트에 오류가 있는지 검사할 수 있다.
개념적으로 보면:
송신 측
데이터 + 체크섬
↓
네트워크
↓
수신 측
체크섬 확인
↓
정상 / 오류
데이터에 문제가 있다고 판단되면 해당 세그먼트를 정상적으로 처리하지 않고, TCP의 다른 메커니즘과 함께 재전송이 이루어질 수 있다.
TCP가 사용하는 기능을 정리하면
지금까지 나온 내용을 한 번에 보면 조금 더 이해하기 쉽다.
| 기능 | 역할 |
|---|---|
| 시퀀스 번호 | 데이터 순서 관리 |
| ACK | 정상적인 수신 확인 |
| 재전송 | 손실된 데이터 다시 전송 |
| 체크섬 | 데이터 오류 확인 |
| 흐름 제어 | 수신자가 처리할 수 있는 양에 맞춰 전송 |
| 혼잡 제어 | 네트워크 상황에 따라 전송량 조절 |
각각 따로 보면 별것 아닌 것처럼 보이지만, 이것들이 같이 동작하면서 TCP의 신뢰성을 만들어낸다.
TCP가 파일 전송에 적합한 이유
파일 다운로드를 생각해보면 TCP의 특징이 더 쉽게 보인다.
예를 들어 1GB짜리 파일을 받는데 중간의 데이터 일부가 사라졌다고 해보자.
단순히 데이터를 빠르게 보내는 것만 생각한다면 파일이 완성되더라도 내용이 일부 깨질 수 있다.
하지만 TCP에서는 데이터의 순서를 관리하고 손실된 데이터를 재전송하면서 수신 측이 올바른 데이터 스트림을 받을 수 있도록 한다.
그래서 웹이나 파일 전송처럼 데이터가 정확하게 전달되는 것이 중요한 서비스에서 TCP가 오랫동안 사용되어 왔다.
그렇다고 TCP가 무조건 느린 것은 아니다
TCP의 기능이 많다 보니 TCP는 느리고 UDP는 빠르다고 단순하게 생각하기 쉽다.
하지만 실제 속도는 그렇게 단순하게 결정되지 않는다.
네트워크 환경이나 서버 성능, 지연시간, 혼잡 상태 등 여러 요소가 영향을 준다.
TCP는 신뢰성을 확보하기 위해 확인과 제어 과정을 수행하기 때문에 그만큼 처리해야 할 일이 많다는 정도로 이해하는 것이 좋다.
반대로 UDP는 이런 기능을 기본적으로 제공하지 않기 때문에 애플리케이션이 필요한 기능만 직접 구현할 수도 있다.
TCP는 모든 문제를 해결해주는 것은 아니다
여기서 하나 짚고 넘어갈 부분이 있다.
TCP가 데이터를 안전하게 전달한다고 해서 인터넷에서 데이터가 절대로 손실되지 않는다는 뜻은 아니다.
TCP는 손실을 감지하고 재전송하는 등의 방법으로 신뢰성 있는 바이트 스트림을 제공하지만, 네트워크 자체가 항상 정상적으로 유지된다는 보장은 없다.
예를 들어 서버가 꺼지거나 네트워크 연결 자체가 끊어진다면 TCP도 데이터를 계속 전달할 수는 없다.
결국 TCP는 네트워크의 불확실성을 어느 정도 감당하면서 애플리케이션이 데이터를 안정적으로 주고받을 수 있도록 도와주는 역할을 한다고 보는 게 맞다.
TCP 데이터 전달 과정을 간단하게 보면
전체적인 흐름을 묶어보면 다음과 같다.
애플리케이션 데이터
↓
TCP 세그먼트 생성
↓
시퀀스 번호 부여
↓
네트워크 전송
↓
수신 측 데이터 확인
↓
ACK 전달
↓
손실 또는 오류 발생 시 재전송
↓
순서에 맞게 데이터 처리
여기에 수신 버퍼와 네트워크 상황까지 고려해서 전송량을 조절한다.
처음에는 TCP가 그냥 “확실하게 데이터를 보내주는 프로토콜”이라고만 생각했는데, 실제로 들여다보면 꽤 많은 기능이 서로 연결되어 있다.
시퀀스 번호로 순서를 관리하고, ACK로 수신 상태를 확인하고, 문제가 생기면 재전송한다.
그리고 수신자가 감당할 수 있는 양과 네트워크 혼잡 상태까지 확인하면서 전송량을 조절한다.
결국 TCP의 신뢰성은 특정 기능 하나 때문에 만들어지는 것이 아니라 여러 제어 기능이 함께 동작한 결과라고 보는 게 가장 이해하기 편하다.
앞에서 살펴본 3-Way Handshake가 TCP 연결을 시작하기 위한 과정이었다면, 이번에 본 시퀀스 번호와 ACK, 재전송 등은 연결된 이후 실제 데이터를 안정적으로 주고받기 위한 핵심 기능이라고 생각하면 된다.