TCP VS UDP

이정빈·2024년 4월 30일

네트워크

목록 보기
6/10
post-thumbnail

TCP란

TCP는 Transmission Control Protocol의 약자로 인터넷에서 데이터를 주고받을 때 사용하는 통신 규약이다. TCP는 연결형 서비스를 지원하고, 데이터의 신뢰성을 보장한다. TCP의 특징은 아래와 같다.

  • 송신부와 수신부의 연결을 확인하는 연결형 서비스
  • 패킷의 전송 순서가 보장됨
  • 패킷의 수신 여부를 확인함
  • 송신부와 수신부가 1대1 통신을 함
  • 데이터의 무손실을 보장 - > 신뢰성이 높음
  • 데이터의 송수신 속도가 느림
  • 패킷 교환방식은 패킷이 전달되는 회선이 정해져있는 가상 회선 방식을 사용함
  • 패킷 교환 방식
    1. 가상회선 방식: 데이터를 주고받기 전에 패킷을 전송할 경로인 가상 회선을 설정하여 모든 패킷을 같은 경로로 전송
    2. 데이터그램 방식: 패킷마다 최적의 경로로 전송하는 방식 -> 송신부에서 보낸 패킷 순서와 수신부에서 받은 패킷 순서가 다를 수 있음

TCP 핸드 셰이킹

TCP에서는 연결형 서비스를 지원하기 위해 송신부와 수신부를 연결하는 과정을 거친다. 연결을 시작할 때는 3-way 핸드셰이킹을 연결을 종료할 때는 4-way 핸드셰이킹을 수행한다. 핸드셰이킹 과정에서는 송신부와 수신부 간의 연결을 제어하도록 플래그(flag)값 들을 주고받는다. 플래그들은 아래와 같다.

  • SYN: Synchronization(동기화)의 약자로, 연결을 생성할 때 사용한다.
  • FIN: Finish(종료)의 약자로, 연결을 끊을 때 사용한다.
  • ACK: Acknowledgement(승인)의 약자로, 데이터를 전송하면 수신자가 받았음을 알릴 때 사용한다.
  • RST: Reset(초기화)의 약자로, 연결을 재설정할 때 사용한다.
  • PSH: Push(밀기)의 약자로, 빠른 응답이 필요한 데이터를 어플리케이션 계층으로 즉시 전송할 때 사용한다.
  • URG: Urgent(긴급)의 약자로, 다른 데이터보다 우선순위가 높은 데이터를 전송할 때 사용한다.

3-way 핸드셰이킹

3-way 핸드셰이킹은 상대방 컴퓨터와 TCP 연결을 수립하는 과정으로 데이터의 정확한 전달을 위해 필요하다. 이 과정을 통해 서버와 클라이언트가 데이터를 주고받을 준비가 되었음을 보장한다.

  1. 클라이언트가 랜덤 숫자 N을 생성한 뒤 서버와 연결하고자 서버에세 SYN 메시지와 N을 보낸다. 이 때 클라이언트는 서버로부터 ACK가 오기 전까지 SYN_SENT 상태가 된다.

  2. 서버가 SYN 메시지를 받고 연결 요청을 수락하는 ACK메시지에 N+1 값을 같이 담는다 또한 랜덤숫자 M을 생성하여 서버와의 연결을 확인하기 위해 SYN 메시지에 M을 담는다. 이후 ACK 메시지와 SYN 메시지를 클라이언트에게 보낸다. 이 때 서버는 클라이언트로부터 ACK가 오기 전까지 SYN_RECEIVED 상태가 된다.

  3. 클라이언트는 서버로부터 온 ACK와 SYN 메시지를 받으면 연결을 확인했다는 의미로 서버에게 ACK 메시지와 M+1 값을 같이 보낸다. 이후 ESTABLISHED 상태가 된다. 서버도 ACK 메시지와 M+1을 받은 뒤 ESTABLISHED 상태가 된다.

4-way 핸드셰이킹

4-way 핸드셰이킹은 상대방 컴퓨터와 TCP 연결을 해제할 때 이루어지는 과정이다.

  1. 클라이언트가 서버에게 연결을 종료하고자 FIN 메시지를 보낸다. 이 때 클라이언트는 FIN_WAIT 1 상태가 된다.

  2. 서버는 클라이언트의 FIN 메시지를 받았다는 ACK 메시지를 보내고 CLOSE_WAIT 상태가 된다. 이후 서버는 앱을 종료하는 등의 연결을 종료하기 위한 준비를 한다. 클라이언트는 ACK 메시지를 받고 FIN_WAIT 2 상태가 된다.

  3. 서버는 연결을 종료할 준비를 마치면 클라이언트에게 FIN 메시지를 보내고 LAST_WAIT 상태가 된다.

  4. 클라이언트는 FIN 메시지를 받고 ACK 메시지를 서버로 보낸 뒤 TIME_WAIT 상태가 된다. 이후 일정 시간 후 자동으로 CLOSED 상태가 된다. 서버는 ACK 메시지를 받은 뒤 CLOSED 상태가 된다.

  • 4번 과정에서 클라이언트가 일정시간동안 TIME_WAIT를 유지하는 이유
    서버가 FIN 메시지 전에 보낸 패킷이 지연되어 클라이언트에게 FIN 메시지보다 늦게 수신되어 발생하는 패킷 유실에 대비하기 위함이다.
  • 가상회선 방식을 사용하는데 어떻게 FIN보다 먼저 보낸 패킷이 클라이언트에 FIN 메시지보다 늦게 수신될 수 있지?
    가상회선 방식은 경로를 설정하여 데이터를 전송하는 방식이기 때문에 일반적으로 데이터가 고정된 경로를 통해 전송되지만, 네트워크에서는 다양한 요인에 의해 패킷이 지연되거나 경로가 변경될 수 있기 때문이다.

TCP 흐름 제어(Flow Control)

흐름 제어는 클라이언트와 서버의 데이터 처리 속도 차이 때문에 발생하는 데이터 손실을 방지하는 방법이다.

1. 정지-대기(stop-wait)

클라이언트에서 서버에 데이터를 보낸 후 서버로부터 ACK를 기다린 후 다음 데이터를 보내는 방식이다. 만약 일정 시간동안 기다렸는데 ACK를 받지 못하면 이전에 전송한 패킷을 재전송 한다. ACK를 기다린 뒤에 데이터를 보낼 수 있으므로 시간 측면에서 효율이 떨어진다.

2. 슬라이딩 윈도우(sliding window)

클라이언트에서 서버의 ACK를 확인하지 않고 서버에서 설정한 윈도우 크기만큼 데이터를 연속적으로 보낼 수 있게 해서 데이터 흐름을 제어하는 방식이다. 윈도우 크기는 응답받지 않고 보낼 수 있는 데이터릐 최대 개수를 의미하며 연결을 시작하는 3-way 핸드셰이킹에서 정해진다.

예를 들어 윈도우 크기가 3인 경우 클라이언트는 한번에 데이터를 3개까지 보낼 수 있다. 이 때 1개의 시나리오를 살펴보자

  1. 클라이언트는 1, 2, 3을 보낼 수 있지만 1과 2만 보냈다.

  2. 서버는 1은 받았고 2는 오다가 유실되어 1만 받았다는 클라이언트로 ACK를 보낸다.

  3. 클라이언트는 아직 2의 ACK를 받지 못했지만 이제 2, 3, 4를 보낼 수 있는 상태가 된다.

이 시나리오에서 주목해야할 점은 클라이언트가 2의 ACK를 받지 못했지만 1의 ACK를 받았으므로 윈도우가 서버가 받은 개수만큼 왼쪽으로 가서 4도 보낼 수 있는 상태가 되었다는 것이다.

이처럼 슬라이딩 윈도우 방식은 서버의 데이터 수신 여부와 상관없이 일정 크기의 데이터를 연속적으로 보내서 ACK 메시지를 받아야만 데이터를 보낼 수 있는 정지-대기(stop-wait) 방식을 보완한다.


혼잡 제어(Congestion Control)

혼잡 제어는 클라이언트의 데이터 전달 속도와 네트워크 속도 차이로 데이터 손실이 발생하는 것을 방지하기 위한 방법이다. 여기서 혼잡이란 네트워크에 패킷 수가 과도하게 증가하는 현상이다. 혼잡이 발생하여 네트워크에 패킷이 쌓이면서 클라이언트가 일정 시간 동안 ACK 메시지를 받지 못하면 클라이언트는 데이터 전송에 실패했다고 생각하여 서버에 데이터를 재전송한다. 이는 네트워크의 혼잡을 가중시키고 이런 과정이 악순환된다.
따라 TCP는 혼잡 윈도우의 크기를 조절하여 혼잡에 대응한다.

  • 혼잡 윈도우
    혼잡 윈도우는 송신 측 TCP Congestion Window 크기를 말하며, 송신 측이 Ack없이 한 번에 데이터를 보내는 크기로, 혼잡 제어를 위해 계속 변동하는 값이다. 혼잡 윈도우가 커지면 데이터 전송 속도가 빨라지고, 혼잡 윈도우가 작아지면 전송 속도가 느려진다.

1. AIMD(Additive Increase Multiplicative Decrease)

데이터를 전송할 때 합 증가 방식으로 혼잡 윈도우의 크기를 더해가면서 키우고, 데이터 손실이 발생하면 혼잡 윈도우의 크기를 곱 감소 방식으로 1/2배로 줄이는 방식이다.

예를 들어 혼잡 윈도우 크기가 1에서 시작을 하면 1 -> 2 -> 3 - > 4 이런식으로 커지다가 혼잡 윈도우 크기가 4일 때 데이터 손실이 발생하면 혼잡 윈도우 크기를 4 * 1/2 = 2 로 줄이는 방식이다.

이 방식을 사용하면 시간이 지남에 따라 여러 클라이언트 간에 네트워크 대역폭을 공평하게 사용할 수 있다. 하지만 데이터 손실이 발생하면 윈도우 크기의 감소 폭이 증가 폭보다 훨씬 크므로 네트워크 대역폭을 넓게 사용하기까지 시간이 오래걸린다는 단점이 있다.

2. 느린 시작(Slow Start)

윈도우 크기가 1인 상태에서 시작해 ACK 메시지를 수신할 때마다 혼잡 윈도우 크기를 1씩 증가하다가 혼잡이 발생하면 혼잡 윈도우 크기를 1로 줄이는 방식이다. 즉, 한 주기가 지나면 Window Size는 2배가 된다(예를 들어 윈도우 사이즈가 3일 때 데이터 3개를 보내면 ACK가 3개가 와서 윈도우 사이즈가 6이 된다).

이 방식을 사용하면 처음부터 패킷을 보낼 수 있는 최대 개수만큼 보내는 것이 아니라 1개 부터 점차 늘려가므로 "느린 시작" 이라는 이름이 붙었다. 이 방식은 AIMD의 단점인 초기에 전송 가능한 패킷 수가 적다는 단점을 보완한다(AIMD는 합 증가이지만 느린 시작은 지수 증가이다).

3. 혼잡 회피(Congestion Avoidance)

윈도우 크기가 지수 형태로 계속 증가하다가 혼잡이 발생하는 방지하기 위해 윈도우 최대 크기 임계점(threshold)을 정하는 방식이다. 윈도우 크기가 임계점에 도달하면 윈도우의 크기가 선형적으로 증가하게 된다. ACK 메시지를 받지 못해서 타임아웃이 발생하면 타임아웃이 발생한 시점에서 윈도우 크기의 절반을 임계점으로 정하고 윈도우 크기는 초기값으로 변경한다.

4. 빠른 회복(Fast Recovery)

혼잡이 발생하면 혼잡 윈도우 크기를 1로 줄이지 않고 절반으로 줄이고 선형 증가시키는 방식이다. 즉, 빠른 회복을 적용했을 때는 혼잡이 1번 발생한 뒤에는 순수한 AIMD 방식으로 동작하게 된다.

5. 빠른 재전송(Fast Retransmit)

중복 ACK가 3번 발생하면 해당 시점의 윈도우 크기를 1/2로 줄이고, ACK 메시지를 받으면 다시 윈도우 크기를 키우는 방식이다. 중복 ACK는 패킷이 순서대로 도착하지 않아 받아야할 차례의 패킷을 ACK 메시지와 함께 요청하는 것을 의미한다.

빠른 재전송의 예시는 아래와 같다.

  1. 클라이언트가 서버에게 패킷 1, 2, 3 번을 보냈다.
  2. 서버에게 ack를 받기 전 클라이언트가 서버에게 패킷 4번을 보냈다.
  3. 서버가 1, 2번은 받았지만 3번은 받지 못했다. 따라서 ack2, ack3를 보낸다.
  4. 클라이언트가 ack2, 3을 받고 패킷 5, 6을 보낸다(4번은 아까 보냈으므로).
  5. 서버에 패킷 4번이 도착하면 패킷 3번을 먼저 보내라는 ack3을 보낸다.
  6. 서버에 패킷 5, 6번이 도착하면 패킷 3번을 먼저 보내라는 ack3을 보낸다.
  7. 클라이언트가 ack 3을 총 4번(중복은 3번) 받았으므로 패킷 3을 전송한 뒤 윈도우 크기를 1/2로 줄인다.

오류 제어(Error Control)

오류 제어는 통신 중 데이터에 오류 또는 유실이 발생할 때 데이터의 신뢰성을 보장하기 위해 오류를 제어하는 방식이다. 데이터에 오류 또는 유실을 인지하는 경우는 아래와 같다.

  • 서버에서 잘못된 데이터를 받았다는 응답인 NAK(Negative Acknowledgement) 메시지를 보낸 경우

  • 3 중복 ACK가 발생한 경우

  • 서버로부터 ACK를 받지 못해 타임아웃이 발생한 경우

데이터 오류 혹은 유실을 제어하는 방법은 3가지가 있다.

1. 정지-대기

흐름제어에서 보았던 방식이다. 클라이언트가 데이터를 1개만 보내고 ACK를 받으면 다음 데이터를 보내는 방식이다. 이 방식은 데이터를 1개만 보내고 메시지를 기다려야하는 부분이 비효율적이라 ARQ(Auto Repeat Request) 방식이 사용된다. ARQ는 재전송 요청을 의미한다.

2. Go-Back_N ARQ

클라이언트에서 연속적으로 데이터를 보낼 때 누락된 데이터가 있으면 클라이언트에서 해당 데이터부터 재전송하는 방식이다.
예를 들어 클라이언트가 패킷 0부터 3까지 보냈는데 ACK2를 받으면 패킷 2부터 3까지 다시 보낸다.

3. Selective-Repeat ARQ

클라이언트에서 연속적으로 데이터를 보낼 때 누락된 데이터가 있으면 서버에서 해당 데이터만 재전송을 요청하는 방식이다.
예를 들어 아래의 시나리오가 있다.

  1. 클라이언트가 패킷 0부터 3까지 보냈는데 서버에서 패킷 0,1,3은 받았지만 패킷 2만 받지 못했다. 따라서 서버는 ACK2를 보낸다.
  2. ACK2를 받으면 패킷 2만 다시 보낸다(패킷 3은 보내지 않는다).
  3. 서버에서 2를 받고 3은 아까 받았으므로 ACK 4를 보낸다.
  4. 클라이언트는 ACK4를 받고 다시 패킷 4부터 보낸다.

이 방식은 특정 패킷만 재전송한다는 장점이 있지만 서버가 받은 패킷을 재정렬하는 과정이 추가로 필요하다는 단점이 있다.


UDP란

UDP(User Datagram Protocol)는 TCP와 마찬가지로 전송계층에 해당하는 네트워크 프로토콜이다. UDP는 서버와 클라이언트 간 연결을 지원하지 않고 데이터그램 형태의 통신을 지원한다. 그래서 TCP와 달리 3-way 핸드셰이킹 같은 과정 없이 패킷을 바로 송수신한다. 이 방식은 신뢰성이 낮지만 속도가 빠르다는 장점이 있다.

  • 데이터 그램: 독립적인 관계를 지니는 패킷

UDP의 특징

  • 서버와 클라이언트의 연결이 보장되지 않는 비연결형 서비스이다.

  • 패킷이 서로 다른 회선으로 교환될 수 있는 데이터그램 패킷 교환 방식이다.

  • 클라이언트에서 보낸 패킷의 순서와 서버에서 받는 패킷의 순서가 다를 수 있다.

  • 패킷의 수신 여부를 확인하지 않는다.

  • 1대1 통신, 1대多통신, 多대多 통신이 모두 가능하다.

  • 데이터의 신뢰성이 낮다.

  • 데이터의 전송 속도가 빠르다.

UDP의 오류 검출

UDP는 최소한의 신뢰성을 보장하기 위해 체크섬(checksum) 방식으로 오류를 검출할 수 있다. 체크섬은 데이터의 무결성을 보장하는 간단한 방법이다. 체크섬을 통한 오류 검출은 아래의 순서로 이루어진다.

  1. 체크섬을 만들기 위한 데이터(UDP 헤더, IP 헤더의 일부정보 등)를 모두 더한다(2진수임).
    더한 값을 1의 보수를 취해 체크섬을 만든다.

  2. 송신자가 UDP로 데이터 전송 시 체크섬을 체크섬 영역에 넣어서 세그먼트에 같이 전송한다.

  3. 수신자는 수신된 세그먼트에 대해 동일한 방식으로 체크섬을 만든다.

  4. 헤더의 체크섬과 일치 하는지 비교하여 수신된 세그먼트의 오류를 검출한다.

하지만 체크섬의 한계가 있다. 데이터를 각각 비교하는 것이 아니라 데이터들의 값의 합을 비교하는 방법이므로 데이터의 순서가 바뀌거나 오류가 발생해도 체크섬이 같은 경우도 있다. 따라서 오류를 100% 검출할 수는 없다. 또한 UDP 체크섬은 선택 사항이므로 송신자가 체크섬을 0으로 보내면 수신자는 체크섬을 계산하지 않는다.

UDP 사용 사례

UDP는 RTP(Real Time Protocol), Multicast, DNS 등에서 사용된다.

RTP(Real Time Protocol)

전화를 하고 있다 다고 가정해보자. "여","보","세","요"라는 4개의 데이터를 전송했는데, "세"를 못받았다고 다시 보내달라고 하면(TCP를 사용하면) "여보요세"가 될 것이다. 이럴 때는 그냥 "여보X요"로 전달하는게 낫다. 따라서 UDP를 사용한다.

DNS

누군가 DNS 서비스를 요청할 때마다 TCP처럼 Session을 맺고 통신한다면 속도도 느리고, 서버 리소스도 엄청나게 소모될 것이다. 따라서 UDP를 사용한다.

Multicast

TV와 같이 1:N으로 통신하는 방식에서 한 사람이 데이터를 받지 못했다고 재전송을 요청한다고 가정해보자. 제대로 받은 사람들도 해당 데이터를 다시 받아서 처리해야 한다는 문제점이 발생할 수 있기 때문에 UDP를 사용한다.


TCP VS UDP

TCP와 UDP의 차이점은 많기 때문에 글로 쓰기보다 표로 정리하는 것이 좋다고 생각했다.

참고:

profile
사용자의 입장에서 생각하며 문제를 해결하는 백엔드 개발자입니다✍

0개의 댓글