인터넷(그리고 일반적인 TCP/IP 네트워크)은 애플리케이션에게 2개의 전송(transport) 프로토콜을 제공한다.
Cf. 네트워크 애플리케이션을 설계할 때 애플리케이션 개발자는 이 두 가지 트랜스포트 프로토콜 중 하나를 명시해야 한다.
UDP와 TCP의 가장 기본적인 기능은 종단 시스템 사이의 IP 전달 서비스를 종단 시스템에서 동작하는 두 프로세스 간의 전달 서비스로 확장하는 것이다. ‘호스트 대 호스트 전달’을 ‘프로세스 대 프로세스 전달’로 확장하는 것을 트랜스포트 계층 다중화(transport-layer multiplexing)와 역다중화(demultiplexing)라고 부른다. UDP와 TCP는 헤더에 오류 검출 필드를 포함함으로써 무결성 검사를 제공한다.
이러한 최소한의 두 가지 트랜스포트 계층 서비스(프로세스 대 프로세스 데이터 전달과 오류 검출)가 UDP가 제공하는 유일한 두 가지 서비스다. UDP는 IP와 마찬가지로 비신뢰적인 서비스며, 하나의 프로세스에 의해 전송된 데이터가 손상되지 않고(일부 또는 데이터 전부) 목적지 프로세스에 도착한다는 것을 보장하지 않는다.
반면에, TCP는 애플리케이션에 몇 가지 추가적인 서비스를 제공한다. 가장 먼저 TCP는 신뢰적인 데이터 전송(reliable data transfer)을 제공한다. 흐름 제어, 순서 번호, 확인 응답, 타이머를 사용함으로써 TCP는 송신하는 프로세스로부터 수신하는 프로세스에게 데이터가 순서대로 정확하게 전달되도록 확실하게 한다. 이처럼 TCP는 종단 시스템 간에 IP의 비신뢰적인 서비스를 프로세스 사이의 신뢰적인 데이터 전송 서비스로 만들어준다. 또한 TCP는 혼잡 제어(congestion control)를 사용한다. 송신측의 TCP가 네트워크에 보낼 수 있는 트래픽을 조절함으로써 각 TCP 연결이 링크의 대역폭을 공유하여 통과하도록 도와준다. 반면에 UDP 트래픽을 조절되지 않으며, UDP 트랜스포트 프로토콜을 사용하는 애플리케이션은 허용이 되는 한 그것이 만족하는 어떤 속도로든 전송할 수 있다.
💡 다중화(Multiplexing)와 역다중화(Demultiplexing)
트랜스포트 계층 세그먼트의 데이터를 올바른 소켓으로 전달하는 작업을 역다중화(demultiplexing)라고 한다. 출발지 호스트에서 소켓으로부터 데이터를 모으고, 이에 대한 세그먼트를 생성하기 위해 각 데이터에 헤더 정보(나중에 역다중화에 사용)로 캡슐화하고, 그 세그먼트들을 네트워크 계층으로 전달하는 작업을 다중화(multiplexing)라고 한다.
UDP는 트랜스포트 계층 프로토콜이 할 수 있는 최소 기능으로 동작한다.
TCP는 신뢰적인 데이터 전송 서비스를 제공하지만 UDP는 그렇지 않으므로 TCP가 항상 더 선호될까? 그렇지 않다. 왜냐하면 많은 애플리케이션은 다음과 같은 이유로 UDP에 더 적합하다.
애플리케이션 | 애플리케이션 계층 프로토콜 | 하위 트랜스포트 프로토콜 |
---|---|---|
전자메일 | SMTP | TCP |
원결 터미널 접속 | 텔넷 | TCP |
보안 원격 터미널 접속 | SSH | TCP |
웹 | HTTP, HTTP/3 | TCP(HTTP), UDP(HTTP/3) |
파일 전송 | FTP | TCP |
원격 파일 서버 | NFS | 일반적으로 UDP |
스트리밍 멀티미디어 | DASH | TCP |
인터넷 폰 | 통상 독점 프로토콜 | UDP 또는 TCP |
네트워크 관리 | SNMP | 일반적으로 UDP |
이름 변환 | DNS | 일반적으로 UDP |
UDP 세그먼트 구조는 RFC 768에 정의되어 있다. 애플리케이션 데이터는 UDP 데이터그램의 데이터 필드에 위치한다. UDP 헤더는 2바이트씩 구성된 단 4개의 필드만을 갖는다.
✅ Internet Checksum
Goal: 전송된 세그먼트에서 오류를 감지한다. (i.e., flipped bits)
- 송신자:
- UDP 세그먼트(UDP 헤더 필드 및 IP 주소 포함)의 내용을 16비트 정수 시퀀스로 처리
- checksum: 세그먼트 내용에 덧셈(1의 보수합)
- UDP checksum 필드에 checksum 값 입력
- 수신자:
- 수신한 세그먼트의 checksum 계산
- 계산된 checksum이 checksum 필드 값과 같은지 확인:
- not equal - error detected
- equal - no error detected
TCP는 연결형, 신뢰적인 트랜스포트 프로토콜이다. 신뢰적인 데이터 전송을 제공하기 위해 오류 검출, 재전송, 누적 확인응답, 타이머, 순서 번호와 확인응답 번호를 위한 헤더 필드를 포함한다.
TCP 세그먼트는 헤더 필드와 데이터 필드로 구성되어 있다.
세그먼트 데이터 필드의 크기는 MSS(maximum segment size, 최대 세그먼트 크기)로 제한된다.
💡 MSS(maximum segment size, 최대 세그먼트 크기)
MSS는 일반적으로 로컬 송신 호스트에 의해 전송될 수 있는 가장 큰 링크 계층 프레임의 길이(최대 전송단위(maximum transmision unit, MTU))에 의해 일단 결정되고, 그런 후에 TCP 세그먼트(IP 데이터그램 안에 캡슐화되었을 때)와 TCP/IP 헤더 길이(통상 40바이트)가 단일 링크 계층 프레임에 딱 맞도록 하여 정해진다.
UDP처럼 헤더는 상위 계층 애플리케이션으로부터 다중화와 역다중화를 하는 데 사용하는 source and destionation port number(출발지와 목적지 포트 번호)를 포함한다. 또한 UDP처럼 헤더는 checksum field(체크섬 필드)를 포함한다. TCP 세그먼트 헤더는 또한 다음과 같은 필드를 포함한다.
32비트 sequence number field(순서 번호 필드)와 32비트 acknowledgement number field(확인응답 번호 필드)는 신뢰적인 데이터 전송 서비스 구현에서 TCP 송신자와 수신자에 의해 사용된다.
16비트 receive window(수신 윈도) 필드는 흐름 제어에 사용된다. 이는 수신자가 받아들이려는 바이트의 크기를 나타내는 데 사용된다.
4비트 header length field(헤더 길이 필드)는 32비트 word 단위로 TCP 헤더의 길이를 나타낸다. TCP 헤더는 TCP option 필드 때문에 가변적인 길이가 될 수 있다(일반적으로, 옵션 필드는 일반적인 TCP 길이가 20바이트가 되도록 비어 있다).
선택적이고 가변적인 길이의 option field(옵션 필드)는 송신자와 수신자가 최대 세그먼트 크기(MSS)를 협상하거나 고속 네트워크에서 사용하기 위한 윈도 확장 요소로 이용된다. 타임스탬프 옵션 또한 정의된다.
flag field(플래그 필드)는 6비트를 포함한다. ACK 비트는 확인응답 필드에 있는 값이 유용함을 가리키는 데 사용된다. 즉, 이 세그먼트는 성공적으로 수신된 세그먼트에 대한 확인응답을 포함한다. RST, SYN, FIN비트는 연결 설정과 해제에 사용된다. PSH 비트가 설정될 때, 이것은 수신자와 데이터를 상위 계층에 즉시 전달해야 한다는 것을 가리킨다. 마지막으로 URG 비트는 이 세그먼트에서 송신 측 상위 계층 개체가 ‘긴급’으로 표시하는 데이터임을 가리킨다. 이 긴급 데이터의 마지막 바이트의 위치는 16비트의 urgent data point field(긴급 데이터 포인터 필드)에 의해 가리켜진다.
데이터를 교환하기 전에, 송신자와 수신자는 “handshake”를 수행하여 연결을 설정한다.
하나의 호스트(클라이언트)에서 운영되는 프로세스가 다른 호스트(서버) 안의 또 다른 프로세스와 연결을 시작하길 원한다고 가정하자. 먼저 클라이언트 애플리케이션 프로세스는 서버에 있는 프로세스와 연결 설정하기를 원한다는 것을 클라이언트 TCP에게 알린다. 그러면 클라이언트 안의 TCP는 다음과 같은 방법으로 TCP를 이용해 서버와 TCP 연결 설정을 시작한다.
1단계 — 먼저 클라이언트 측 TCP는 서버 TCP에게 SYN 세그먼트를 송신한다. TCP 세그먼트의 헤더에 SYN 비트라고 불리는 하나의 flag 비트를 1로 설정하고, 최초의 순서 번호(client_isn
)를 임의로 선택하여 최초의 TCP SYN 세그먼트의 순서 번호(seq #) 필드에 이 번호를 넣는다. 이 세그먼트는 IP 데이터그램 안에서 캡슐화되고 서버로 송신된다.
Cf. 특정 보안 공격[CERT 2001-09, RFC 4987]을 피하고자 client_isn을 임의 추출하는 것에 유의해야 한다.
2단계 — TCP SYN 세그먼트를 포함하는 IP 데이터그램이 서버 호스트에 도착하면, 서버는 데이터그램으로부터 TCP SYN 세그먼트를 추출하고, 연결에 TCP 버퍼와 변수를 할당한다. 그리고 클라이언트 TCP로 연결 승인 세그먼트를 송신한다. 세그먼트 헤더에는 3개의 중요한 정보가 포함되어 있다. 첫째, SYN 비트는 1로 설정된다. 둘째, TCP 세그먼트 헤더의 확인응답 필드는 client_isn+1
로 설정된다. 마지막으로, 서버는 자신의 최초의 순서 번호(server_isn
)를 선택하고, TCP 세그먼트 헤더의 순서 번호 필드에 이 값을 넣는다. 연결 승인 세그먼트는 때때로 SYNACK 세그먼트로 불린다.
3단계 — 연결 승인 세그먼트를 수신하면, 클라이언트는 연결에 버퍼와 변수를 할당한다. 그다음에 클라이언트 호스트는 서버로 또 다른 세그먼트를 송신한다. 이 마지막 세그먼트가 서버의 연결 승인 세그먼트를 확인(ack=server_isn+1
)하는 것이다. 연결이 설정되었기 때문에 SYN 비트는 0으로 설정된다. 3-way handshake의 세 번째 단계는 클라이언트에서 서버로의 데이터를 세그먼트 페이로드에 운반할 수 있다.
위의 세 단계가 완료되면, 클라이언트와 서버 호스트들은 각각 서로에게 데이터를 포함하는 세그먼트를 보낼 수 있다. 이 각각의 다음의 세그먼트에서 SYN 비트는 0으로 설정된다. 연결 설정을 위해 두 호스트 사이에서 3개의 패킷이 송신되므로 TCP 연결 설정 절차를 3-way handshake라고 부른다.
TCP 연결에 참여하는 두 프로세스 중 하나가 연결을 끝낼 수 있다. 연결이 끝날 때, 호스트의 ‘자원’(버퍼와 변수)는 회수된다.
클라이언트가 연결 종료를 결정한다고 가정하자.
1단계 — 클라이언트 애플리케이션 프로세스는 종료 명령을 내리고, 이것은 클라이언트 TCP가 서버 프로세스에게 특정 TCP 세그먼트를 보내도록 한다. 이 세그먼트는 1로 설정된 FIN 비트라 불리는 flag 비트를 세그먼트 헤더에 포함한다.
2단계 — 서버가 이 세그먼트를 수신하면, 서버는 클라이언트에게 ACK(확인응답) 세그먼트를 보낸다.
3단계 — 그다음에 FIN 비트가 1로 설정된 자신의 종료 세그먼트를 송신한다.
4단계 — 마지막으로 클라이언트는 서버의 종료 세그먼트에 ACK(확인응답)을 한다. 이 시점에서 두 호스트의 모든 자원은 할당이 해제된다.
TCP 연결의 각 종단에서 호스트들은 연결에 대한 개별 수신 버퍼를 설정한다. TCP 연결이 순서대로 올바르게 바이트를 수신할 때 TCP는 데이터를 수신 버퍼에 저장한다. 애플리케이션이 데이터를 읽는 속도가 비교적 느리다면, 송신자가 점점 데이터를 빠르게 전송함으로써 연결의 수신 버퍼에 아주 쉽게 오버플로를 발생시킨다.
이처럼 TCP는 송신자가 수신자의 버퍼를 오버플로시키는 것을 방지하기 위해 애플리케이션에게 흐름 제어 서비스(flow-control service)를 제공한다. 흐름 제어는 수신하는 애플리케이션이 읽는 속도와 송신자가 전송하는 속도를 같게 한다.
TCP는 송신자가 receive window(수신 윈도)라는 변수를 유지하여 흐름 제어를 제공한다. 수신 윈도는 수신 측에서 가용한 버퍼 공간이 얼마나 되는지를 송신자에게 알려주는 데 사용된다.
흐름 제어는 혼잡이 실제로 발생할 때 데이터의 흐름을 통제하기 위해 사용되는 혼잡 제어와는 구별된다.
매번 전송한 패킷에 대해 확인 응답을 받아야만 그 다음 패킷을 전송하는 방법이다.
수신측에서 설정한 window 크기만큼 송신측에서 확인응답(ACK) 없이 세그먼트를 전송할 수 있게 하여 데이터 흐름을 동적으로 조절하는 제어 기법이다.
전송은 되었지만, ACK을 받지 못한 byte의 숫자를 파악하기 위해 사용하는 프로토콜이다.
먼저 window에 포함되는 모든 패킷을 전송하고, 그 패킷들의 전달이 확인되는대로 이 window를 옆으로 옮기면서 그 다음 패킷들을 전송한다.
💡 window
TCP/IP를 사용하는 모든 호스트들은 송신하기 위한 window 하나와 수신하기 위한 window 하나를 갖고 있다. 호스트들은 실제 데이터를 보내기 전에 3-way handshaking을 통해 수신 호스트의 receive window size에 자신의 send window size를 맞추게 된다.
각 호스트는 정보를 빨리 보내기 위하여 정해진 시간 내에 보낼 수 있는 최대의 패킷을 보내는데, 만약 한 라우터에 데이터가 몰릴 경우, 혼잡 현상이 발생하여 정해진 시간 내에 받은 패킷들을 모두 처리할 수 없게 된다. 이런 경우 호스트들은 데이터 재전송을 하게 되고 결국 혼잡만 가중시켜 오버플로우나 데이터 손실을 발생시킨다. 따라서 이러한 네트워크의 혼잡을 피하기 위해 송신측에서 보내는 데이터의 전송속도를 강제로 줄이게 되는데, 이러한 작업을 혼잡 제어(congestion control)라고 한다.
흐름 제어가 송신측과 수신측 사이의 전송 속도를 조절하는 반면, 혼잡 제어는 호스트와 라우터를 포함한 보다 넓은 관접에서 전송 문제를 다룬다.
TCP 혼잡 제어의 핵심은 바로 cwnd(congestion window) 값을 잘 조절하는 것이다.
처음에 패킷을 하나씩 보내고 이것이 문제없이 도착하면 window 크기(단위 시간 내에 보내는 패킷의 수)를 1씩 증가시켜가면서 전송하는 방법이다. 만일 패킷 전송을 실패하거나 일정한 시간을 넘으면 패킷을 보내는 속도를 절반으로 줄인다.
이 방식은 공평한 방식으로, 여러 호스트가 한 네트워크를 공유하고 있으면 나중에 진입하는 쪽이 처음에는 불리하지만 시간이 흐르면 평형 상태로 수렴하게 되는 특징이 있다.
문제점은 초기에 네트워크의 높은 대역폭을 사용하지 못하여 오랜 시간이 걸리게 되고, 네트워크가 혼잡해지는 상황을 미리 감지하지는 못한다. 즉, 네트워크가 혼잡해지고 나서야 대역폭을 줄이는 방식이다.
AIMD 방식이 네트워크의 수용량 주변에서는 효율적으로 작동하지만, 처음에 전송 속도를 올리는 데 걸리는 시간이 너무 길다는 단점이 있다.
Slow Start 방식은 AIMD 방식과 마찬가지로 패킷을 하나씩 보내는 것부터 시작한다. 그러나 이 방식은 패킷이 문제없이 도착하면 각각의 ACK 패킷마다 window 크기를 1씩 늘린다. 즉, 한 주기가 지나면 window 크기가 2배로 된다. 따라서 전송 속도는 AIMD와는 다르게 지수 함수 꼴로 증가한다. 대신에 혼잡 현상이 발생하면 창 크기를 1로 떨어뜨린다. 처음에는 네트워크의 수용량을 예상할 수 있는 정보가 없지만 한번 혼잡 현상이 발생하고 나면 네트워크의 수용량을 어느 정도 예상할 수 있으므로 혼잡 현상이 발생하였던 창 크기의 절반까지는 이전처럼 지수 함수 꼴로 window 크기를 증가시키고 그 이후부터는 완만하게 1씩 증가시킨다.
이전의 TCP 동작은 처음에 최대한 보낼 수 있는 만큼의 패킷을 보내는 것으로 시작하고, Slow Start는 이것과 달리 window 크기를 1에서부터 시작하여 지수함수 꼴로 증가시켜가면서 네트워크의 수용량을 감지하기에 Slow Start라고 불린다.
이 방식은 AIMD 방식보다 더 효율적인 방법이지만 마찬가지로 혼잡한 상황이 된 경우에는 타임아웃이 될 때까지 기다리는 동안 큰 시간의 공백이 있다.
빠른 재전송(Fast Retransmit)은 TCP의 혼잡 제어에 추가된 정책이다.
패킷을 받는 쪽에서 먼저 도착해야 할 패킷이 도착하지 않고 다음 패킷이 도착한 경우에도 ACK 패킷을 보낸다. 단, 순서대로 잘 도착한 마지막 패킷의 다음 패킷의 순번을 ACK 패킷에 실어서 보낸다. 따라서 중간에 패킷 하나가 손실되게 되면 보내는 측에서는 순번이 중복된 ACK 패킷을 받게 되고, 이것을 감지하는 순간 문제가 되는 순번의 패킷을 재전송해 줄 수 있다. 빠른 재전송은 중복된 순번의 패킷을 3개 받으면 재전송을 한다. 그리고 이런 현상이 일어나는 것은 약간 혼잡한 상황이 일어난 것이므로 혼잡을 감지하고 window 크기를 줄이게 된다.
빠른 회복 정책(Fast Recovery)은 혼잡한 상태가 되면 window 크기를 1로 줄이지 않고 반으로 줄이고 선형 증가시키는 방법이다. 빠른 회복 정책까지 적용하면 혼잡 상황을 한번 겪고 나서부터는 순수한 AIMD 방식으로 동작한다.
Cf. [Animation] TCP Congestion Control