TCP란
TCP(Transmission Control Protocol)는 전송 계층에 해당하는 네트워크 프로토콜로 연결형 서비스를 지원하고 데이터의 신뢰성을 보장한다.
TCP의 특징은 다음과 같다.
•
송신부와 수신부의 연결을 확인하는 연결형 서비스다.
•
패킷 교환 방식은 패킷이 전달되는 회선이 정해져 있는 가상 회선 방식이다.
•
패킷의 전송 순서가 보장된다.
•
패킷의 수신 여부를 확인한다.
•
송신부와 수신부는 1:1 통신을 한다.
•
데이터 손실이 없음을 보장하므로 신뢰성이 높다.
•
데이터의 송수신 속도가 느리다.
패킷 교환 방식
•
가상 회선 방식 : 데이터를 주고받기 전에 패킷을 전송할 경로인 가상 회선을 설정해서 모든 패킷을 같은 경로로 전송한다.
•
데이터그램 방식 : 패킷마다 최적의 경로로 전송되는 방식으로 송신부에서 보낸 패킷의 순서와 수신부에 도착하는 패킷의 순서가 다를 수 있다.
TCP 핸드셰이킹
TCP에서는 연결형 서비스를 지원하기 위해 송신부와 수신부를 연결하는 과정을 거친다.
연결을 시작할 때는 3-way 핸드셰이킹을, 연결을 종료할 때는 4-way 핸드셰이킹을 한다.
핸드셰이킹 과정에서는 송신부와 수신부 간 연결을 제어 및 관리하도록 다음과 같은 플래그(flag) 값을 주고 받는다.
이 중에서 주로 사용하는 플래그 값은 SYN, FIN, ACK이다.
•
SYN
Synchronization(동기화)의 약자로 연결을 생성할 때 사용
•
FIN
Finish(종료)의 약자로 연결을 끊을 때 사용
•
ACK
Acknowledgment(승인)의 약자로 데이터를 전송하면 수신자가 받았음을 알려줄 때 사용
•
RST
Reset(초기화)의 약자로 연결을 재설정할 때 사용
•
PSH
Push(밀다)의 약자로 빠른 응답이 필요한 데이터를 응용 계층으로 즉시 전송할 때 사용
•
URG
Urgent(긴급)의 약자로 다른 데이터보다 우선순위가 높은 데이터를 전송할 때 사용
3-way 핸드셰이킹
3-way 핸드셰이킹은 데이터를 본격적으로 주고받기 전에 상대방 컴퓨터와 세션을 수립하는 과정으로 데이터의 정확한 전달을 위해 필요한 절차이다.
이 과정에서 데이터의 송신자와 수신자 모두 데이터를 주고받을 준비가 되었음을 보장한다.
1.
송신부가 수신부와 연결하기 위해 SYN 메시지를 보내는데, 이때 임의의 숫자 N을 함께 보낸다.
송신부는 수신부로부터 응답이 오기 전까지 SYN_SENT 상태가 된다.
2.
수신부가 송신부로부터 SYN 메시지를 받으면 연결 요청을 수락하는 의미인 ACK 메시지를 전송한다.
ACK 메시지에는 송신부로부터 받은 N에 1을 더한 N+1 값을 함께 보낸다.
수신부에서도 송신부와의 연결을 확인하기 위해 SYN 메시지에 임의의 숫자인 M을 함께 보낸 후 송신부의 응답을 기다린다.
이때 송신부는 SYN_RECEIVED 상태가 된다.
3.
송신부가 수신부로부터 ACK + SYN 메시지를 받으면 연결이 성립되었다는 의미인 ESTABLISHED 상태가 된다.
메시지에 대한 응답으로 ACK 메시지와 수신부로부터 받은 M에 1을 더한 M+1 값을 함께 보낸다.
이때 ACK 메시지에는 송신부에서 전송하려는 데이터가 포함될 수 있다.
송신부로부터 ACK 메시지를 받으면 수신부는 ESTABLISHED 상태가 된다.
송신부와 수신부 간에 번갈아 요청과 응답을 해서 연결을 확인한 후에 본격적으로 데이터 통신을 하게 된다.
이처럼 요청과 응답을 총 3번 주고 받는다고 해서 3-way 핸드셰이킹이라고 한다.
4-way 핸드셰이킹
4-way 핸드셰이킹은 TCP 연결을 해제할 때 이뤄지는 과정이다.
연결을 해제할 때는 이름 그대로 요청과 응답을 총 4번 주고 받게 된다.
1.
송신부가 수신부와의 연결을 종료하려고 FIN 메시지를 보낸다.
이때 송신부는 FIN_WAIT1 상태가 된다.
2.
수신부가 송신부로부터 FIN 메시지를 받으면 이에 대한 응답으로 ACK 메시지를 보낸다.
이때 수신부는 CLOSE_WAIT 상태가 된다.
수신부는 메시지를 보낸 후 앱을 종료하는 등 연결을 종료하기 위한 작업을 한다.
송신부에서는 수신부에서 보낸 ACK 메시지를 받고 FIN_WAIT2 상태가 된다.
3.
수신부에서 연결을 종료할 준비가 끝나면 송신부에 FIN 메시지를 보내고 LAST_WAIT 상태가 된다.
4.
송신부는 서버로부터 받은 FIN 메시지에 응답하기 위해 ACK 메시지를 보내고 TIME_WAIT 상태가 된다.
일정 시간이 지나면 CLOSED 상태가 된다.
일정 시간 동안 TIME_WAIT 상태를 유지하는 이유는 FIN 메시지 전에 보낸 패킷이 FIN 메시지 수신보다 지연되어 발생하는 패킷 유실에 대비하기 위해서다.
또한, 수신부에 ACK 메시지가 제대로 전달되지 않아 연결 해제가 이뤄지지 않는 경우도 대비한다.
수신부는 송신부로부터 ACK 메시지를 받고 CLOSED 상태가 된다.
TCP Keep Alive 패킷
세션이 연결되면 이를 유지하기 위해 일정 시간이 경과한 후 연결을 유지하길 원하는 쪽에서 TCP Keep Alive 패킷을 던져 연결 유지 상태를 확인할 수 있다.
패킷에 대한 응답을 받으면 시간을 처음부터 다시 측정하고, 응답을 받지 못하면 연결을 종료한다.
이는 동일한 송신부로부터 재요청이 오는 경우에 불필요한 3-way 핸드셰이킹을 줄일 수 있다.
또한, FIN 메시지를 받지 못한 경우에 발생할 수 있는 불필요한 좀비 커넥션을 방지할 수 있다.
TCP 제어 방법
TCP의 데이터 신뢰성을 보장하기 위한 제어 방법으로 흐름 제어, 혼잡 제어, 오류 제어가 있다.
흐름 제어
흐름 제어(flow control)는 데이터 송신부와 수신부에서 데이터 처리 속도의 차이 때문에 생기는 데이터 손실을 방지하는 방법이다.
•
정지-대기(stop-wait)
송신부에서 데이터를 보낸 후 수신부로부터 ACK 메시지를 받을 때까지 다음 데이터를 보내지 않고 기다리는 방식이다.
송신부에서 패킷을 보내고 일정 시간 동안 수신부로부터 ACK 메시지를 받지 못하면 패킷을 재전송한다.
간단하지만 이전 메시지에 대한 응답을 받아야만 다음 메시지를 보낼 수 있어서 시간 면에서 비효율적이다.
•
슬라이딩 윈도우(sliding window)
송신부에서 데이터의 수신 여부(ACK)를 확인하지 않고 수신부에서 설정한 윈도우 크기만큼 데이터를 연속적으로 보낼 수 있게 해서 데이터 흐름을 동적으로 제어하는 방식이다.
윈도우 크기는 응답받지 않고도 보낼 수 있는 데이터의 최대 개수를 의미하며 3-way 핸드셰이킹 과정에서 정해진다.
1.
윈도우 크기가 4일 때 송신부에서 데이터 1과 2를 보내고 3과 4는 보낼 수 있지만 아직 보내지 않은 상태다.
2.
수신부에서 데이터 1과 2를 받았다는 ACK 메시지를 보낸다.
3.
송신부는 수신부가 데이터 1과 2를 받은 것을 확인하고 윈도우를 2칸 이동한다.
따라서 3부터 6까지 데이터를 보낼 수 있는 상태가 된다.
송신부에서 데이터 3, 4, 5를 보낸다.
4.
수신부에서 데이터 3과 4를 받았다는 ACK 메시지를 보낸다.
송신부는 수신부에서 데이터 3과 4를 받았다는 ACK 메시지는 받았지만 데이터 5를 받았다는 ACK 메시지는 받지 못해서 윈도우를 2칸만 이동한다.
이제 데이터 7, 8도 보낼 수 있는 상태가 된다.
이처럼 슬라이딩 윈도우 방식은 수신 여부와 상관없이 일정 크기의 데이터를 연속적으로 보내서 ACK 메시지를 받아야만 다음 메시지를 보낼 수 있는 정지-대기 방식의 단점을 보완한다.
혼잡 제어
혼잡 제어(congestion control)는 송신부의 데이터 전달 속도와 네트워크 속도 차이로 데이터 손실이 발생하는 것을 방지하기 위한 방법이다.
혼잡은 네트워크에 패킷 수가 과도하게 증가하는 증상을 의미한다.
혼잡이 발생해 네트워크에 패킷이 쌓이면서 일정 시간 응답을 받지 못하면 송신붕에서는 메시지 전송에 실패했다고 판단해 수신부에 패킷을 재전송한다.
이는 혼잡을 가중해 악순환을 야기한다.
따라서 TCP는 혼잡 윈도우의 크기를 조절해 혼잡에 대응한다.
•
AIMD(Additive Increase Multiplicative Decrease)
데이터를 전달할 때 합 증가(additive increase) 방식으로 혼잡 윈도우의 크기를 더해가면서 키운다.
그리고 데이터 손실이 발생하면 혼잡 윈도우의 크기를 곱 감소(multiplicative decrease) 방식을 적 용해 1/2배와 같이 배수 단위로 줄인다.
AIMD 방식은 시간이 지나면 여러 송신부 간에 네트워크 대역폭을 공평하게 사용할 수 있게 된다.
하지만 데이터 유실이 발생하면 윈도우 크기 증가폭 대비 윈도우 크기 감소폭이 크기 때문에 네트워크의 대역폭을 넓게 사용하기까지 시간이 오래 걸린다는 단점이 있다.
•
느린 시작(slow start)
윈도우 크기가 1인 상태에서 시작해 ACK 메시지를 수신할 때마다 윈도우 크기를 1씩 늘려나간다.
그러다 혼잡이 발생하면 윈도우 크기를 1로 확 줄이는 방식이다.
이 방식은 패킷을 처음부터 보낼 수 있는 최대 개수만큼 보내는 것이 아니라 1개부터 점차 늘려나가서 느린 시작이라는 이름이 붙었다.
이처럼 전송 가능한 패킷 수(윈도우 크기)를 지수 함수 형태로 늘리는 점은 AIMD 방식에서 초기에 전송 가능한 패킷 수가 적다는 단점을 보완한다.
•
혼잡 회피(congestion avoidance)
윈도우 크기가 지수 함수 형태로 증가하다가 혼잡이 발생하는 것을 방지하기 위해 윈도우 크기에 대한 임계점(threshold)을 정하는 방식이다.
윈도우 크기가 임계점에 도달하면 윈도우 크기를 선형적으로 증가하게 한다.
ACK 메시지를 받지 못해 타임아웃이 발생하면 타임아웃이 발생한 시점에서 윈도우 크기의 절반을 임계점으로 설정하고 윈도우 크기를 초기값으로 변경한다.
•
빠른 회복(fast recovery)
혼잡이 발생하면 혼잡 윈도우 크기를 절반으로 줄인 후 선형적으로 증가하는 방식이다.
즉, 혼잡이 처음 발생하면 AIMD 방식으로 동작한다.
•
빠른 재전송(fast retransmit)
Duplicate ACK가 3번 발생하면 해당 시점의 윈도우 크기를 1/2로 줄인다.
그 뒤로 ACK 메시지를 받으면 다시 윈도우 크기를 키우는 방식이다.
Duplicate ACK는 패킷이 순서대로 도착하지 않아서 받아야 할 차례의 패킷을 ACK 메시지와 함께 요청하는 것을 뜻한다.
즉, Duplicate ACK가 3번 발생하면 혼잡이 발생했다고 판단해 윈도우 크기를 조정한다.
대표적인 현대 TCP 혼잡 제어 알고리즘
•
TCP Cubic (2008)
현재 리눅스와 윈도우 등 주요 운영체제에서 기본적으로 사용되는 혼잡 제어 알고리즘이다.
특히 고속, 고지연 네트워크 환경에서 더 나은 성능을 발휘하도록 설계되었다.
비선형 함수(3차 함수)를 사용하여 혼잡 회피 단계에서 빠르게 회복하면서도 네트워크에 부담을 주지 않는 방식으로 동작하며 고속 네트워크에서도 높은 대역폭을 더 효율적으로 사용할 수 있다.
•
TCP BBR(Bottleneck Bandwidth and Round-trip propagation time) (2016)
구글이 개발한 최신 혼잡 제어 알고리즘으로 패킷 손실에 의존해 혼잡을 감지하는 전통적인 TCP 알고리즘과는 달리 네트워크의 대역폭과 지연 시간을 기반으로 최적의 전송 속도를 결정한다.
패킷 손실이나 RTT 변화보다는 실제 네트워크 병목 대역폭을 측정해 그에 맞춰 전송 속도를 조절하고 클라우드 서버와 같은 고성능 네트워크 환경에서 높은 대역폭과 낮은 지연 시간을 동시에 유지하는 탁월한 성능을 발휘한다.
오류 제어
오류 제어(error control)는 통신 중 데이터에 오류 또는 유실이 발생할 때 데이터의 신뢰성을 보장하기 위해 오류를 제어하는 방식이다.
데이터에 오류 또는 유실 발생을 인지하는 경우는 다음과 같다.
•
수신부에서 잘못된 데이터를 받았다는 응답인 NAK(Negative Acknowledge) 메시지를 보낸 경우
•
3 Duplicate ACK가 발생할 때
•
수신부로부터 ACK 메시지를 받지 못해 타임아웃이 발생할 때
데이터에 오류 또는 유실이 발생하면 다음과 같은 방법으로 오류 제어를 한다.
•
정지-대기
송신한 패킷에 대한 ACK 메시지를 일정 시간 동안 받지 못해 타임아웃이 발생하면 해당 패킷을 다시 보내는 방식이다.
흐름 제어에서 나왔던 방식으로 데이터 유실을 간단히 처리할 수 있어서 오류 제어에서도 사용된다.
하지만 이 방식은 송신부에서 데이터를 1개만 보내고 메시지를 기다려야 하기 때문에 ARQ 방식이 사용된다.
ARQ(Automatic Repeat Request)는 재전송 요청을 의미한다.
•
Go-Back-N ARQ
송신부에서 연속적으로 데이터를 보냈을 때 누락된 데이터가 있으면 송신부에서 해당 데이터부터 재전송하는 방식이다.
예를 들어, 송신부에서 패킷 0부터 패킷 2까지 보냈을 때 수신부에서 ACK 3 메시지를 보내면 송신부는 다음에 패킷 3부터 보낸다.
그리고 패킷 3부터 패킷 5까지 보냈을 때 ACK 4 메시지를 받으면 패킷 4와 패킷 5를 재전송한다.
•
Selective-Repeat ARQ
송신부에서 연속적으로 데이터를 보냈을 때 누락된 데이터가 있으면 수신부에서 해당 데이터만 재전송을 요청하는 방식이다.
예를 들어, 수신부에서 패킷 0부터 패킷 2까지 잘 수신하면 패킷 3을 보내라는 의미의 ACK 3 메시지를 보낸다.
그러고 나서 송신부에서 패킷 3부터 패킷 5까지 보냈을 때 패킷 4를 받지 못했다면 패킷 4를 보내라는 의미로 ACK 4 메시지를 보낸다.
이 요청을 받은 송신부는 패킷 4를 다시 보내고 이를 받은 수신부는 패킷 6을 요청한다.
특정 패킷만을 재전송한다는 점은 효율적으로 보이지만 받은 패킷을 재정렬하는 로직이 추가로 필요하다.
UDP
UDP(User Datagram Protocol)는 TCP와 마찬가지로 전송계층에 해당하는 네트워크 프로토콜이다.
UDP는 송신부와 수신부 간 연결을 지원하지 않고 데이터그램 형태의 통신을 지원한다.
그래서 TCP와 달리 3-way 핸드셰이킹 같은 과정 없이 패킷을 바로 송수신하게 된다.
이 방식은 신뢰성이 낮지만 속도가 빠르다는 장점이 있다.
UCP의 특징은 다음과 같다.
•
송신부와 수신부의 연결이 보장되지 않는 비연결형 서비스다.
•
패킷이 서로 다른 회선으로 교환될 수 있는 데이터그램 패킷 교환 방식이다.
•
송신부에서 전달한 패킷 순서와 수신부에서 받은 패킷 순서가 다를 수 있다.
•
패킷의 수신 여부를 확인하지 않는다.
•
1:1 통신, 1:N 통신, N:N 통신 모두 가능하다.
•
데이터의 신뢰성이 낮다.
•
데이터의 전송 속도가 빠르다.
TCP와 UDP의 차이점
구분 | TCP | UDP |
연결 방식 | 연결형 서비스 | 비연결형 서비스 |
패킷 교환 방식 | 가상 회선 방식 | 데이터그램 방식 |
전송 순서 | 순서 보장 | 순서가 바뀔 수 있음 |
수신 여부 | 확인 | 확인하지 않음 |
통신 방식 | 1:1 통신 | 1:1, 1:N, N:N 통신 |
신뢰성 | 높음 | 낮음 |
속도 | 느림 | 빠름 |
UDP의 오류 검출
UDP는 최소한의 신뢰성을 보장하기 위해 체크섬(checksum) 방식으로 오류를 검출할 수 있다.
체크섬은 데이터의 무결성을 보장하는 간단한 방법으로 체크섬을 만들기 위한 데이터를 모두 더한다.
이때 오버플로되는 캐리가 발생하면 해당 캐리를 떼서 데이터에 다시 더한 후 1의 보수를 취해 체크섬을 만든다.
UDP 송신부는 UDP의 헤더, IP 헤더의 일부 정보(발신 IP 주소, 수신 IP 주소, 프로토콜 ID 등)와 데이터로 체크섬 값을 생성한다.
생성한 체크섬 값을 UDP 헤더의 체크섬 영역에 넣어서 수신부에 보낸다.
수신부는 체크섬을 포함한 모든 값을 더해 비트가 모두 1이 나오는지 확인한다.
여기서 비트가 모두 1이라는 뜻은 송신부와 동일한 체크섬 값이 나온다는 것을 의미한다.
하지만 체크섬을 이용해도 오류를 100% 검출할 수 있는 것은 아니다.
데이터를 각각 비교하는 것이 아니라 값을 더해 확인하는 방식이라서 데이터의 순서가 바뀌거나 오류가 발생해도 체크섬이 같은 경우가 있기 때문이다.
또한 UDP의 체크섬은 선택 사항이므로 송신부에서 체크섬 값을 0으로 보내면 수신부는 체크섬을 계산하지 않는다.