Transport services and protocols
전송 계층은 다른 호스트에서 실행되는 응용 프로그램 프로세스 간의 논리적 통신을 제공한다. 이 계층의 주된 역할은 데이터 전송을 관리하고, 오류를 검출 및 복구하며, 데이터 흐름을 제어하는 것이다.
전송 프로토콜이 종단 시스템에서 수행하는 작업들은 다음과 같다:
- 송신자: 응용 프로그램 메시지를 세그먼트로 분할하고, 이를 네트워크 계층으로 전달한다.
- 수신자: 세그먼트를 재조립하여 메시지를 만들고, 이를 응용 계층으로 전달한다.
인터넷 응용 프로그램에 사용 가능한 두 가지 전송 프로토콜이 있다:
- TCP (Transmission Control Protocol): 신뢰성 있는 스트림 서비스를 제공한다. 즉, 데이터는 순서대로 도착하며 중복되거나 누락되지 않는다. TCP는 성능보다 신뢰성을 중요시하는 애플리케이션에 적합하다.
- UDP (User Datagram Protocol): 연결 설정 없이 데이터그램 서비스를 제공한다. UDP는 최소한의 오버헤드와 함께 빠른 전송을 원하는 애플리케이션에 적합하지만, 신뢰성은 보장하지 않는다.
따라서 해당 애플리케이션이 필요로 하는 요구사항과 상황에 따라 TCP와 UDP 중에서 선택해야 한다.
Transport vs Network layer
네트워크 계층은 호스트 간의 논리적 통신을 제공한다. 이 계층에서는 IP 주소를 기반으로 데이터 패킷을 송수신하는 호스트를 식별하고, 이들 패킷이 네트워크를 통해 올바르게 라우팅되도록 관리한다.
전송 계층은 프로세스 간의 논리적 통신을 제공한다. 이 계층에서는 포트 번호를 사용하여 데이터가 올바른 응용 프로그램 프로세스에 도달하도록 관리한다.
전송 계층은 네트워크 계층의 서비스에 의존하며, 이를 확장한다. 예를 들어, TCP (Transmission Control Protocol)는 네트워크 계층에서 제공하는 비신뢰성 있는 패킷 전달 서비스 위에 신뢰성 있는 데이터 스트림 전송 서비스를 제공한다. 이와 같이 전송 계층은 네트워크 계층의 기능을 보완하고 개선하여 애플리케이션 사이의 더 나은 커뮤니케이션을 가능하게 한다.
Transport Layer actions
전송 계층은 sender와 receiver의 역할로 구분할 수 있다.
Sender:
- 전송 계층은 응용 계층에서 메시지를 전달 받는다. 그런 다음 세그먼트 헤더 필드의 값을 결정한다. 이 헤더 필드에는 포트 번호, 순서 정보, 오류 검사 값 등이 포함될 수 있다.
- 이렇게 결정된 헤더 필드 값과 함께 응용 계층의 메시지를 합하여 세그먼트를 생성한다.
- 생성된 세그먼트는 IP(인터넷 프로토콜) 즉, 네트워크 계층으로 전달된다. 이곳에서 세그먼트는 패킷으로 패키징되고, 이 패킷은 목적지 호스트로 라우팅된다.
Receiver:
- 전송 계층은 IP 즉, 네트워크 계층으로부터 세그먼트를 수신한다. 이후 헤더 값들을 확인한다. 이 값들은 데이터의 무결성을 검사하고, 데이터가 올바른 순서로 재조립되는지 확인하는 데 사용된다.
- 헤더 값을 확인한 후, 전송 계층은 응용 계층 메시지를 세그먼트에서 추출한다.
- 마지막으로, 전송 계층은 메시지를 소켓을 통해 응용 프로그램까지 역다중화(demultiplexes)한다. 여기서 역다중화란 포트 번호와 같은 정보를 사용하여 각 메시지가 올바른 목적지 응용 프로그램에 도달하도록 하는 과정을 말한다.
Multiplexing/Demultiplexing
전송 계층에서 다중화(multiplexing)와 역다중화(demultiplexing)는 데이터를 올바른 소스와 목적지 사이로 전달하는 중요한 과정이다.
송신자에서의 다중화:
- 각 소켓들로부터 데이터 단위(응용 계층 메시지)를 모아 캡슐화 한 뒤, 전송 헤더를 추가한다. 이 헤더에는 포트 번호와 같은 정보가 포함되어 있어, 나중에 수신자에서 역다중화할 때 사용된다.
- 이렇게 캡슐화 세그먼트들을 네트워크 계층으로 전달한다.
수신자에서의 역다중화:
- 수신자의 전송 계층은 네트워크 계층으로부터 세그먼트를 받는다.
- 세그먼트 헤더의 정보(예: 목적지 포트 번호)를 확인하여 해당 세그먼트가 어느 소켓으로 가야 하는지 결정한다.
- 적절한 소켓을 찾아낸 후, 그곳으로 세그먼트 내의 응용 계층 메시지를 전달한다.
이런 방식으로, 다중화와 역다중화 과정을 통해 여러 응용 프로그램 프로세스가 동일한 네트워크 인터페이스 및 IP 주소를 공유하면서도 서로 독립적인 통신을 유지할 수 있다.
Demultiplexing works
네트워크 계층에서 호스트가 IP 데이터그램을 받으면, 각 데이터그램은 출처 IP 주소와 목적지 IP 주소를 가지고 있다. 이러한 정보는 네트워크 계층에서 패킷이 올바른 호스트로 라우팅되도록 하는데 사용된다.
각 IP 데이터그램은 하나의 전송 계층 세그먼트를 운반한다. 이 세그먼트는 출처 포트 번호와 목적지 포트 번호를 가지고 있다. 이 정보는 전송 계층에서 세그먼트가 올바른 소켓으로 전달되도록 하는데 사용된다.
따라서, 호스트는 이러한 IP 주소와 포트 번호를 사용하여 세그먼트를 적절한 소켓으로 보낸다. 이렇게 하면 여러 응용 프로그램이 동시에 네트워크 통신을 수행할 수 있게 된다.
Connectionless demultiplexing
소켓을 생성할 때, 호스트 로컬 포트 번호를 지정해야 한다. 이 포트 번호는 해당 호스트 내에서 해당 소켓을 고유하게 식별하는 데 사용된다.
UDP 소켓에 데이터그램을 보낼 때, 목적지 IP 주소와 목적지 포트 번호를 지정해야 한다. 이 정보는 데이터그램이 올바른 호스트와 응용 프로그램으로 전달되도록 하는데 사용된다.
수신 호스트가 UDP 세그먼트를 받으면, 세그먼트의 목적지 포트 번호를 확인한 다음, 이 포트 번호에 해당하는 소켓으로 UDP 세그먼트를 전달한다.
출처 IP 주소나 출처 포트 번호가 다른 데이터그램이라도 같은 목적지 포트 번호를 가지면, 수신 호스트에서 같은 소켓으로 전달된다. 이는 여러 출처로부터 오는 통신이 하나의 응용 프로그램(즉, 하나의 소켓)에서 처리될 수 있도록 하는 기능이다. 즉, 출처와 상관 없이 목적지 포트 번호와 목적지 IP 주소 만을 고려한다.
Connection-oriented demultiplexing
연결 지향형 역다중화(connection-oriented demultiplexing)는 TCP(Transmission Control Protocol)와 같은 연결 지향형 프로토콜에서 사용되는 방식이다.
TCP 소켓은 4-튜플(four-tuple)로 식별된다. 이 4-튜플에는 다음과 같은 정보가 포함된다:
- 출처 IP 주소
- 출처 포트 번호
- 목적지 IP 주소
- 목적지 포트 번호
수신자의 전송 계층은 이 4개의 값(4-튜플)을 모두 사용하여 세그먼트를 적절한 소켓으로 전달한다.
서버는 여러 개의 동시 TCP 소켓을 지원할 수 있다:
- 각 소켓은 고유한 4-튜플로 식별된다.
- 각 소켓은 다른 연결 중인 클라이언트와 연관되어 있다.
따라서, 연결 지향형 역다중화에서 중요한 것은 각 TCP 세그먼트가 특정 '연결'에 바인딩되며, 그 '연결'을 나타내는 4-튜플에 따라 적절한 소켓으로 전달된다는 점이다. 즉, connection-oriented demultiplexing는 connectionless demultiplexing과는 달리 출처의 IP 주소와 포트번호가 추가로 필요하며 각 연결된 클라이언트마다 다른 소켓을 지닌다.
Multiplexing/Demultiplexing Summary
다중화(multiplexing)와 역다중화(demultiplexing)는 세그먼트 또는 데이터그램의 헤더 필드 값에 기반하여 수행된다. 이들은 여러 데이터 스트림을 하나의 채널로 결합하거나(다중화), 하나의 채널에서 여러 데이터 스트림으로 분리하는(역다중화) 과정을 의미한다.
- UDP(User Datagram Protocol): UDP에서는 목적지 포트 번호만을 사용하여 역다중화를 수행한다. 이 포트 번호를 통해 호스트는 수신된 세그먼트를 올바른 소켓으로 전달할 수 있다.
- TCP(Transmission Control Protocol): TCP에서는 4-튜플(source and destination IP addresses, and port numbers)을 사용하여 역다중화를 수행한다. 이 4-튜플은 각 TCP 연결을 고유하게 식별하며, 호스트가 수신된 세그먼트를 올바른 소켓으로 전달할 수 있게 한다.
이렇게 다중화와 역다중화는 모든 네트워크 계층에서 발생할 수 있다. 예를 들어, 데이터 링크 계층에서 MAC 주소를 사용하여 프레임을 적절한 장치로 전달하거나, 네트워크 계층에서 IP 주소를 사용하여 패킷을 적절한 호스트로 라우팅하는 것도 역다중화의 한 형태라고 볼 수 있다.
UDP
UDP(User Datagram Protocol)는 "간단하고 기본적인" 인터넷 전송 프로토콜로, 다음과 같은 특징을 가지고 있다:
- best effort 서비스: best effort 서비스란 최대한 노력은 하지만 확실한 전송을 보장하지 않는 서비스이다. UDP는 세그먼트를 최대한 전송하려고 하지만, 세그먼트가 손실되거나 응용 프로그램에 순서대로 전달되지 않을 수 있다.
- 연결 없음(connectionless): UDP 송신자와 수신자 사이에 핸드셰이킹이 없다. 각 UDP 세그먼트는 다른 세그먼트와 독립적으로 처리된다. 연결 설정이 필요 없으므로 RTT(Round-Trip Time) 지연을 추가하지 않는다.
- 단순함: 송신자와 수신자 모두에서 연결 상태를 유지할 필요가 없다.
- 작은 헤더 크기: TCP보다 헤더 크기가 작아 오버헤드가 적다.
- 혼잡 제어 없음: UDP는 데이터를 원하는 만큼 빠르게 보낼 수 있다. 이러한 특성 때문에 네트워크가 혼잡해져도 계속해서 기능할 수 있다.
UDP의 이러한 특징들은 실시간 응용 프로그램(예: VoIP, 비디오 스트리밍 등)에서 유용하게 사용된다. 이런 응용 프로그램들은 데이터의 신속한 전달을 위해 일부 패킷 손실을 받아들일 준비가 되어 있으며, 따라서 UDP의 "best effort" 서비스 모델이 적합하다.
UDP(User Datagram Protocol)는 다음과 같은 상황에서 사용된다:
- 스트리밍 멀티미디어 애플리케이션: 이러한 애플리케이션은 일부 데이터 손실을 허용할 수 있지만, 데이터 전송률에 민감하다. 따라서, UDP의 best effort서비스와 연결 없는 특성이 적합하다.
- DNS(Domain Name System): DNS 쿼리는 작고, 응답 시간이 중요하며, 일부 손실을 감수할 수 있다.
- SNMP(Simple Network Management Protocol): 네트워크 관리 정보를 수집하고 조직하는데 사용되며, 신속한 전달과 간단한 프로토콜이 필요하다.
- HTTP/3: 이전 버전의 HTTP와 달리, HTTP/3는 QUIC라는 UDP 기반의 프로토콜을 사용한다.
또한 혼잡 제어도 응용 계층에서 추가할 수 있다. TCP와 달리 UDP 자체에는 내장된 혼잡 제어 메커니즘이 없으므로, 네트워크 혼잡 시 데이터 전송률을 조절하는 등의 기능을 응용 계층에서 직접 구현해야 한다.
UDP segment header
UDP(User Datagram Protocol) 세그먼트 헤더는 매우 간단하며, 다음의 4개 필드로 구성되어 있다:
- 출발지 포트 번호(Source Port Number): 이 필드는 선택 사항이며, 세그먼트를 보내는 프로세스의 포트 번호를 나타낸다. 이 정보는 수신자가 응답을 돌려보낼 때 사용된다.
- 목적지 포트 번호(Destination Port Number): 이 필드는 세그먼트가 전송되어야 하는 목적지 프로세스의 포트 번호를 나타낸다.
- 길이(Length): 이 필드는 헤더와 데이터 모두를 포함한 UDP 세그먼트의 전체 바이트 수를 나타낸다. 최소 길이는 8 바이트(헤더만 있을 경우)이고, 최대 길이는 65,535 바이트다.
- 체크섬(Checksum): 이 필드는 오류 검출을 위한 것으로, 송신자가 세그먼트를 만들 때 계산하여 채워넣고, 수신자가 세그먼트를 받았을 때 다시 계산하여 비교한다. 만약 두 값이 일치하지 않으면 세그먼트에 오류가 있음을 알 수 있다.
UDP actions
UDP(User Datagram Protocol) 송신자와 수신자의 동작은 다음과 같다:
UDP 송신자의 동작:
- 응용 계층으로부터 메시지를 전달받는다.
- UDP 세그먼트 헤더 필드 값들을 결정한다.
- UDP 세그먼트를 생성한다.
- 생성된 세그먼트를 IP(Internet Protocol)로 전달한다.
UDP 수신자의 동작:
- IP로부터 세그먼트를 받는다.
- UDP 체크섬 헤더 값을 확인한다.
- 응용 계층 메시지를 추출한다.
- 메시지를 소켓을 통해 응용 계층으로 역다중화하여 전달한다.
이렇게, UDP는 단순하고 효율적인 데이터 전송을 제공하지만, 신뢰성이나 순서 보장 등의 기능은 제공하지 않는다. 이러한 기능이 필요한 경우에는 해당 기능들은 응용 계층에서 구현되어야 한다.
Internet checksum
UDP(User Datagram Protocol) 세그먼트의 체크섬은 송신자와 수신자 모두에 의해 계산되며, 오류 검출을 위해 사용된다. 이는 다음과 같이 동작한다:
송신자:
- UDP 세그먼트의 내용(UDP 헤더 필드와 IP 주소를 포함)을 16비트 정수의 시퀀스로 취급한다.
- 세그먼트 내용의 합계를 계산한다(1의 보수 합).
- 이 체크섬 값은 UDP 체크섬 필드에 넣어진다.
수신자:
- 수신한 세그먼트의 체크섬을 계산한다.
- 계산한 체크섬이 체크섬 필드 값과 같은지 확인한다
하지만, "같으면 오류가 없는 것으로 감지된다"고 해도 실제로는 그래도 오류가 있을 수 있다. 이것은 "오류가 없음"을 보장하는 것이 아니라 "오류를 발견하지 못했음"을 의미하기 때문이다. 이러한 한계 때문에 더 나은 오류 검출 방법들이 개발되었다 (예: CRC, 해시 함수 등).
UDP Summary
UDP(User Datagram Protocol)는 "no frills" 프로토콜이다. 이 말은 UDP가 기본적인 서비스만 제공하며, 고급 기능을 제공하지 않는다는 것을 의미한다. 예를 들어, 세그먼트가 손실되거나 순서대로 전달되지 않을 수 있다.
UDP는 "best effort" 서비스를 제공한다. "최선을 다하는" 방식이 아닌 "보내고 최선의 결과를 바라는" 방식이다.
그러나 UDP에도 장점이 있다:
- 설정 또는 핸드셰이킹이 필요 없다(따라서 RTT(Round Trip Time) 발생하지 않음).
- 네트워크 서비스가 손상된 상황에서도 작동할 수 있다.
- 신뢰성을 돕기 위해 체크섬을 사용한다.
- 응용 계층에서 UDP 위에 추가 기능을 구축할 수 있다(예: HTTP/3).
따라서, 복잡한 핸드셰이킹과 오류 복구 메커니즘이 필요 없는 간단한 데이터 전송에 대해서는 UDP가 TCP보다 더 효율적일 수 있다.
Reliable data transfer protocol : rdt
RDT 프로토콜을 통한 데이터 전송 과정은 다음과 같다:
- 응용 계층에서 데이터 보내기: 응용 계층(application layer)에서 데이터를 보내려고 할 때, rdt_send 함수가 호출된다. 이 함수는 주어진 데이터를 패킷 형태로 만들고, 이 패킷을 신뢰성 있는 전송 프로토콜(rdt)에게 준비시킨다.
- 네트워크로 보내기: rdt는 패킷을 네트워크를 통해 보낼 준비가 되면, udt_send 함수를 호출한다. 이 함수는 실제로 패킷을 물리적인 네트워크에 전달한다.
- 패킷 수신하기: 다른 쪽에서 패킷이 도착하면, rdt_rcv 함수가 호출된다. 이 함수는 네트워크에서 들어오는 패킷을 받아들인다.
- 에러 검사 및 복구: rdt_rcv은 에러 검사와 복구 과정을 수행한다. 만약 에러가 발견되면 해당 패킷은 버려지고 재전송이 요청된다.
- 데이터 응용 계층으로 전달하기: 에러 검사 및 복구 과정 후, 올바르게 수신된 패킷의 데이터는 추출되어 응용 계층으로 보내진다(deliver_data).
rdt 1.0
rdt 1.0은 신뢰성 있는 데이터 전송(reliable data transfer) 프로토콜의 가장 간단한 형태이다. 이 프로토콜은 완벽하게 신뢰할 수 있는 채널, 즉 패킷이 손실되거나 손상되지 않는 네트워크 환경을 가정한다.
rdt 1.0의 작동 방식은 다음과 같다:
- 데이터 전송: 송신자는 rdt_send를 통해 데이터를 받으면 make_pkt으로 패킷을 만들고, 이를 네트워크에 전송한다(udt_send).
- 데이터 수신: 수신자는 네트워크에서 패킷을 받아들인다(rdt_rcv). 이 프로토콜에서는 에러 검사가 필요하지 않는다, 왜냐하면 모든 패킷이 정확하게 도착한다고 가정하기 때문이다.
- 데이터 추출 및 전달: 수신자는 extract로 패킷의 데이터를 추출하고 응용 계층으로 보내준다(deliver_data).
rdt 1.0은 매우 단순한 형태의 프로토콜이지만, 실제 세계에서 사용하기에는 불완전하다. 대부분의 네트워크 환경에서는 패킷 손실이나 오류가 발생할 가능성이 있기 때문에, 더 복잡한 에러 검사와 복구 메카니즘이 필요하다.
rdt2.0
rdt2.0의 경우 rdt1.0과 달리 bit error가 발생할 수 있다고 생각하고 만들어진 프로토콜이다. 네트워크 통신에서 패킷의 비트가 뒤집히는 경우, 이를 검출하기 위해 체크섬 같은 에러 검출 메커니즘을 사용한다. 그러나 오류를 감지하는 것만으로는 충분하지 않으며, 복구 메커니즘도 필요하다.
오류 복구에 대한 일반적인 접근 방식은 다음과 같다:
- 확인 응답(ACKs): 수신자가 패킷을 정상적으로 받았음을 명시적으로 송신자에게 알리는 방법이다. 이것은 "패킷이 성공적으로 도착했습니다"라는 메시지를 보내는 것을 의미한다.
- 부정확인응답(NAKs): 수신자가 패킷에 오류가 있음을 명시적으로 송신자에게 알리는 방법이다. 이것은 "패킷에 문제가 있습니다, 다시 보내주세요"라는 메시지를 보내는 것을 의미한다.
- 재전송: 송신자가 NAK 메시지를 받으면 해당 패킷을 다시 전송합니다.
- Stop-and-Wait 프로토콜: 이 프로토콜에서 송신자는 한 번에 하나의 패킷만 전송하고, 수신자의 응답(ACK 또는 NAK)을 기다린다. ACK를 받으면 다음 패킷을 전송하고, NAK를 받으면 현재 패킷을 재전송한다.
rdt2.0 프로토콜의 처리 과정은 bit error가 있을 때와 없을 때로 나누어 살펴볼 수 있다.
에러가 없을 경우:
- 데이터 전송: 송신자는 rdt_send 함수를 통해 데이터를 받아 패킷을 만든다. 이 패킷에는 체크섬 정보가 포함되어 있어서 수신자가 비트 에러를 검출할 수 있게 한다.
- 패킷 네트워크로 보내기: 송신자는 udt_send 함수를 호출하여 패킷을 네트워크에 전송한다.
- 패킷 수신 및 확인응답(ACK) 보내기: 수신자는 rdt_rcv 함수를 통해 네트워크에서 패킷을 받아들인다. 체크섬을 이용하여 비트 에러를 검사하고, 오류가 없으면 ACK(확인응답) 메시지를 송신자에게 보낸다.
- ACK 메시지 받기: 송신자는 ACK 메시지를 받으면 다음 데이터 패킷을 준비한다.
- 데이터 추출 및 전달: 수신자 측에서, 정상적인 패킷이 도착하면 그 안의 데이터가 응용 계층으로 전달된다.(deliver_data)
에러가 있는 경우:
- 데이터 전송: 송신자는 rdt_send 함수를 통해 데이터를 받아 패킷을 만든다. 이 패킷에는 체크섬 정보가 포함되어 있어서 수신자가 비트 에러를 검출할 수 있게 한다.
- 패킷 네트워크로 보내기: 송신자는 udt_send 함수를 호출하여 패킷을 네트워크에 전송한다.
- 패킷 수신 및 에러 검출: 수신자는 rdt_rcv 함수를 통해 네트워크에서 패킷을 받아들인다. 체크섬을 이용하여 비트 에러를 검사하고, 오류가 발견되면 NAK(부정확인응답) 메시지를 송신자에게 보낸다.
- NAK 메시지 받기 및 재전송: 송신자는 NAK 메시지를 받으면 해당 데이터 패킷을 다시 준비하고 전송한다.
- 패킷 수신 및 확인응답(ACK) 보내기: 수신자는 rdt_rcv 함수를 통해 네트워크에서 패킷을 받아들인다. 체크섬을 이용하여 비트 에러를 검사하고, 오류가 없으면 ACK(확인응답) 메시지를 송신자에게 보낸다.
- ACK 메시지 받기: 송신자는 ACK 메시지를 성공적으로 받으면 다음 데이터 패킷을 준비한다.
- 데이터 추출 및 전달: 오류 없이 정상적인 패킷이 도착하면 그 안의 데이터가 응용 계층으로 전달된다(deliver_data).
하지만 rdt 2.0은 다음과 같은 결함을 가지고 있다:
- ACK/NAK 손실: ACK/NAK에 오류가 발생하거나 손실이 생기면 송신자가 이를 무한정 기다리게 된다.
- 패킷 중복 송신: ACK/NAK 신호가 중복으로 발생해 패킷이 재전송될 수 있다.
이러한 문제들은 rdt 2.1과 rdt 2.2에서 개선될 수 있다.
rdt 2.1
rdt 2.1은 패킷에 패킷의 순서(seq #)을 추가한다. rdt 2.1과 같은 Stop-and wait 프로토콜에서는 한번에 하나의 패킷만 전송되므로 0과 1 두 개의 상태만 존재해도 충분하다.
송신자와 수신자의 FSM은 다음과 같다.
송신자:
- 0번 패킷 송신: 송신 측에서는 0번 패킷을 보내고 ACK 0 또는 NAK 0을 기다린다.
- NAK 0을 받은 경우: 수신 측에서 에러가 발생해 송신 측에서 NAK 0을 받는다면 송신 측은 0번 패킷을 다시 전송한다.
- ACK 0을 받은 경우: 패킷이 정상적으로 전달되어 송신 측에서 ACK 0을 받는다면 1번 패킷을 송신한다.
- 1번 패킷 송신: 1번 패킷을 송신했다면 NAK 1이나 ACK1을 기다리고 위 과정을 반복한다.
수신자:
0번 패킷이 오류일 때: NAK 0 신호를 보내고 0번 패킷을 기다린다.
0번 패킷이 오류가 아닐 때: ACK 0 신호를 보내고 1번 패킷을 기다린다.
1번 패킷이 오류일 때: NAK 1 신호를 보내고 1번 패킷을 기다린다.
1번 패킷이 오류가 아닐 때: ACK 1 신호를 보내고 0번 패킷을 기다린다.
rdt 2.2
rdt 2.2는 rdt 2.1과 동일한 기능을 제공하지만, 이 프로토콜은 ACK 메시지만 사용하여 NAK-free 환경을 만든다. 이는 수신자가 오류 없이 받은 마지막 패킷에 대한 ACK를 전송함으로써 구현된다.
rdt 2.2의 주요 특징은 다음과 같다:
- ACK 메시지만 사용: rdt 2.2에서 수신자는 패킷에 문제가 있을 경우 NAK 대신 마지막으로 정상적으로 받은 패킷의 ACK를 재전송한다.
- ACK 메시지에 시퀀스 번호 포함: 수신자는 보내는 모든 ACK 메시지에 해당 패킷의 시퀀스 번호를 명시적으로 포함해야 한다.
- 중복된 ACK 처리: 송신자에서 중복된 ACK가 도착하면, 그것은 패킷이 손실되었거나 손상되었다는 신호로 해석됩니다. 이 경우, 송신자는 현재 패킷을 재전송한다.
rdt 3.0
rdt 2.2는 패킷 손실이 발생할 수 있다는 새로운 가정을 도입한다. 이는 데이터 패킷과 ACK 메시지 모두에 해당됩니다. 예를 들어, 말하고자 하는 내용이 상대방에게 제대로 전달되지 않았다면 우리는 보통 그 내용을 다시 말하곤 한다.
rdt 2.2에서 이와 유사한 접근 방식은 다음과 같다:
- "합리적인" 시간동안 기다림: 송신자는 ACK 메시지를 받기 위해 "합리적인" 시간동안 기다린다. 이를 위해 카운트 다운 타이머를 사용한다.
- 재전송: 만약 해당 시간 내에 ACK 메시지가 도착하지 않으면 현재 패킷을 재전송한다.
- 패킷 또는 ACK의 지연 처리: 만약 패킷 또는 ACK가 단순히 지연되었다면(즉, 실제로 소실되지 않고 나중에 도착한다면), 재전송된 패킷은 중복된다. 이 때문에 수신자는 보내는 모든 ACK 메시지에 해당 패킷의 시그널번호를 명시해야 한다.
패킷이 손실되어 time out이 발생하면 패킷을 재전송한다.
ack이 손실되거나 단순 지연되어 time out이 발생하였을 경우에는 송신 측에서 패킷을 재전송하고, 수신 측은 ack 신호를 보낸 후 중복된 패킷 무시한다.
Performance of rdt 3.0
utilization(효율성)은 전체 시간에서 실제 전송에 사용되는 시간의 비율로 계산된다.
rdt 3.0: pipelined protocols operation
rdt3.0은 rdt2.2의 확장으로, 패킷 손실이 발생할 수 있는 채널에서도 신뢰성 있는 데이터 전송을 보장한다. 이는 타이머를 사용하여 ACK 메시지가 도착하지 않은 경우 패킷을 재전송함으로써 구현된다.
하지만 rdt3.0은 여전히 "stop-and-wait" 프로토콜이다. 즉 송신자는 각 패킷에 대한 ACK를 받을 때까지 기다리고 다음 패킷을 보내지 않는다. 이는 효율성이 떨어질 수 있으므로, 실제 네트워크에서는 종종 파이프라인화된 프로토콜(pipelined protocols)이 사용된다.
파이프라인화된 프로토콜에서는 여러 개의 패킷이 동시에 전송될 수 있다. 즉, 송신자가 첫 번째 패킷에 대한 ACK를 기다리는 동안 두 번째, 세 번째 등의 패킷들도 전송할 수 있다.
파이프라인화된 프로토콜의 예로는 Go-Back-N과 Selective Repeat 등이 있다.
Go-Back-N
Go-Back-N 프로토콜:
- 송신자는 최대 N개의 연속적으로 전송되었지만 아직 ACK가 수신되지 않은 패킷들에 대한 "윈도우"를 유지한다.
- 각 패킷 헤더에는 k-bit 시퀀스 번호가 포함된다.
- 누적 ACK(cumulative ACK) 방식을 사용한다. ACK(n) 메시지는 시그널 번호 n까지 모든 패킷을 수신했다는 것을 의미한다. 송신자가 ACK(n)을 받으면, 윈도우를 앞으로 이동하여 n+1에서 시작하게 한다. 즉 ACK(n)은 "n번 패킷까지 잘 받았다"라는 신호이며, n+1번 패킷부터 보내면 된다는 뜻이기도 하다.
- 가장 오래된 "비행 중인(in-flight)" 패킷(즉, 아직 ACK가 도착하지 않은 패킷)에 대해 타이머를 설정한다.
- 타이머 만료(timeout) 시, 해당 패킷 n과 그보다 높은 시그널번호를 가진 윈도우 내의 모든 패킷들이 재전송된다.
송신자:
송신자는 window 범위 내에 있는 패킷들만을 한꺼번에 전송할 수 있다. send_base는 송신은 했지만 ACK을 받지 못한 패킷 중 가장 첫 번째 것을 가리킨다. nextseqnum은 보낼 수는 있으나 상위 계층에서 요청하지 않아 보내고 있지 않은 패킷들 중 가장 첫 번째 것을 가리킨다.
시그널 번호가 n인 패킷을 받지 못했을 경우, 해당 패킷보다 시그널 번호가 높은 m번 패킷까지 받았더라도 ACK 메세지를 전송하지 않다가 n번 패킷이 오면 ACK(m)을 전송한다.
위 그림에서는 수신측에서 pkt3을 수신받더라도 pkt2가 오지 않았으므로 ack 1을 재전송한다. 송신측에서는 ack 1이 중복되어 왔으므로 무시하고, 그 사이에 pkt 2가 timeout 되어 송신자는 pk2부터 window 범위에 있는 모든 패킷을 재전송한다.
Selective repeat
Selective Repeat 프로토콜에서는 각 패킷에 대해 개별적으로 ACK를 보내고, 필요한 경우 패킷을 버퍼링하여 상위 계층으로 순서대로 전달한다.
Selective Repeat 프로토콜:
- 수신자는 모든 올바르게 수신된 패킷에 대해 개별적으로 ACK를 보낸다.
- 필요에 따라 패킷을 버퍼링하고, 이를 상위 계층으로 순서대로 전달한다.
- 송신자는 각각의 unACKed 패킷에 대해 타임아웃 및 재전송을 담당한다.
- 송신자는 각 unACKed 패킷에 대한 타이머를 유지한다.
- 송신자 윈도우는 N개의 연속적인 시그널 번호들을 포함한다.
- 이 윈도우는 보낸 패킷 중 아직 ACK가 오지 않은 패킷들의 시그널 번호 범위를 제한하는 역할을 한다.
Selective Repeat 프로토콜은 네트워크에서 발생할 수 있는 문제에 더욱 세밀하게 대응할 수 있어, 네트워크 자원 활용과 신뢰성 있는 데이터 전송 면에서 효율적이다.
위 그림에서는 수신자 측에서 pkt2를 받지 못하고 pk3를 받았으므로 pkt3를 버퍼에 저장해두고, ack3를 송신자에게 보낸다. 그러다 pkt2가 timeout되면 송신자는 다시금 pkt2를 수신자에게 보내고, 수신자는 그제야 버퍼에 저장해두었던 패킷들을 상위 계층으로 보낸다.
Selective repeat의 경우 Go-Back-N과는 달리 특정 패킷을 받지 못했더라도, 해당 패킷 이후에 오는 패킷들의 ACK을 보낸다.
요약하자면, Go-Back-N 방식은 수신 측에서 중간에 받지 못한 패킷이 있다면, 해당 패킷부터 다시 전송하는 방식이고, Selective repeat 방식은 중간에 받지 못한 패킷이 있을 경우 이후에 받은 패킷을 버퍼에 저장해두었다가 받지 못했던 패킷을 받으면 한꺼번에 상위 레이어로 보내는 방식이다.
https://code-lab1.tistory.com/27
TCP
다음은 TCP (Transmission Control Protocol)의 주요 특징과 작동 방식을 요약하고 있다:
- Point-to-Point: TCP는 하나의 송신자와 하나의 수신자 간에 데이터를 전송한다.
- 신뢰성: TCP는 데이터를 신뢰성 있게, 정확한 순서대로 전송한. "메시지 경계"가 없기 때문에, 바이트 스트림은 연속적이다.
- Full Duplex Data: TCP는 같은 연결에서 양방향 데이터 흐름을 지원한다.
- MSS(Maximum Segment Size): MSS는 TCP 세그먼트의 최대 크기를 정의한다.
- 누적 ACKs(Cumulative ACKs): 수신된 패킷을 확인하는 데 사용되는 누적 인정 메시지이다.
- 파이프라인화(Pipelining): TCP에서, 네트워크 혼잡 상태와 흐름 제어가 윈도우 크기를 설정하는 데 사용된다.
- 연결 지향적(Connection-Oriented): 송신자와 수신자 사이에서 데이터 교환을 시작하기 전에 제어 메시지를 교환하여 초기 상태를 설정하는 핸드셰이킹 과정을 포함한다.
- 흐름 제어(Flow Controlled): 송신자가 수신자를 압도하지 않도록 흐름 제어 기능을 가진다.
위 내용은 RFC 793, 1122, 2018, 5681 및 7323 등 여러 IETF (Internet Engineering Task Force) 문서에서 설명된 내용으로, 인터넷상에서 신뢰할 수 있는 데이터 전송을 가능하게 만드는 핵심 프로토콜인 TCP에 대한 중요한 이해이다.
TCP structure
TCP 세그먼트 구조는 다음과 같은 필드로 구성되어 있다:
- 시퀀스 번호(Sequence Number): 이는 바이트 스트림에서 데이터의 위치를 식별하는 데 사용된다. 시퀀스 번호는 각 TCP 세그먼트가 전송되는 데이터의 첫 바이트를 가리킨다.
- ACK 번호(Acknowledgement Number): 이 필드에 있는 값은 수신자가 다음에 기대하는 바이트의 시퀀스 번호이다.
- 길이(Length): TCP 헤더의 길이를 나타낸다.
- 인터넷 체크섬(Internet Checksum): 이 필드는 오류 검출을 위해 사용된다.
- C, E 플래그(Congestion Notification Flags): C와 E 플래그는 네트워크 혼잡 상태를 알리기 위해 사용된다.
- TCP 옵션(TCP Options): 선택적인 설정을 제공한다.
- RST, SYN, FIN 플래그(Connection Management Flags): RST, SYN 및 FIN 플래그는 TCP 연결 관리를 위해 사용된다.
- 흐름 제어(Flow Control Window Size Field): 수신자가 받아들일 준비가 된 데이터의 양(# bytes receiver willing to accept)을 지정한다.
- Data: 실제로 전송되어야 하는 어플리케이션 데이터이다.
각 TCP 세그먼트에 대한 정보와 함께 이러한 필드들은 모든 호스트가 서로 정보를 교환하고 네트워크 연결 상태를 추적할 수 있도록 한다.
TCP sequence numbers, ACKs
다음은 TCP의 sequence numbers와 ACK에 대한 설명이다:
- 시퀀스 번호(Sequence Numbers): TCP는 신뢰성 있는 전송을 제공하기 위해 시퀀스 번호를 사용한다. 각 TCP 세그먼트의 첫 바이트는 고유한 시퀀스 번호를 가진다. 이것은 수신자가 세그먼트를 올바른 순서로 재조립하고, 중복된 세그먼트를 식별하게 해준다.
- 확인(Acknowledgements): TCP는 확인 메시지(ACK)를 사용하여 특정 데이터가 성공적으로 수신되었음을 송신자에게 알려준다. ACK에 포함된 번호는 수신자가 다음에 기대하는 바이트의 시퀀스 번호이다.
- 누적 ACK와 순서 없는 세그먼트 처리: 누적 ACK은 수신한 모든 연속된 바이트를 한 번에 확인한다. 즉, 만약 송신자가 시퀀스 1, 2, 3을 보내고 수신자가 이들을 모두 받으면, 수신자는 "4"라고 답하여 이전의 모든 바이트(1, 2 및 3)를 한꺼번에 확인한다.
수신자가 seq 42인 패킷을 받으면 다음 패킷인 seq 43을 보내라는 의미로 ack 43을 보낸다.
TCP timeout interval
그렇다면 timeout의 기준을 어떻게 설정할 수 있을까? timeout 주기를 너무 짧게 설정한다면 불필요한 재전송이 발생할 것이고, 너 길게 설정한다면 제대로 전송되지 않는 패킷이 발생할 것이다.
Timeout Interval을 구하기 위해서는 다음과 같은 값들이 사용된다:
- Sample RTT: 이는 특정 세그먼트의 ACK(acknowledgement)를 수신하는 데 걸린 실제 시간을 나타낸다. 즉, 패킷이 전송된 시점부터 ACK 메시지가 돌아올 때까지의 시간이다. 네트워크 상태의 변화로 인해 이 값은 매우 변동성이 크다.
- Estimated RTT: 이는 지난 여러 번의 Sample RTT 값을 기반으로 계산된 예상 RTT이다. 일반적으로 최근의 Sample RTT에 더 큰 가중치를 부여하고 오래된 것들에는 더 작은 가중치를 부여한다.
- DevRTT: 이는 Estimated RTT와 실제로 측정된 SampleRTT 사이의 편차(deviation)을 나타낸다.
이를 통해 다음과 같은 timeout interval을 구할 수 있다.
TCP sender
각 이벤트에 따라 TCP 송신자가 어떻게 반응하는지를 보여준다.
- 애플리케이션으로부터 데이터 수신: TCP는 받은 데이터로부터 세그먼트를 생성하고, 각 세그먼트에 시퀀스 번호를 부여한다. 시퀀스 번호는 세그먼트의 첫 바이트의 바이트 스트림 번호이다.
- 타이머 시작: 아직 실행 중인 타이머가 없다면 타이머를 시작한다. 이 타이머는 가장 오래된 미확인(ACK되지 않은) 세그먼트에 대한 것으로 생각할 수 있다. 만료 간격은 TimeOutInterval이다. 타임아웃이 발생하면 타임아웃을 일으킨 세그먼트를 재전송하고, 타이머를 다시 시작한다.
- ACK 수신: 이전에 ACK되지 않았던 세그먼트들의 ACK를 받았다면 이를 업데이트한다. 아직 ACK되지 않은 세그먼드가 있다면 타이머를 재시작한다.
TCP 송신자의 이러한 동작 방식 덕분에 네트워크에서 신용할 수 있는 데이터 전송을 할 수 있다.
TCP receiver
- 현재 도착한 세그먼트가 예상대로 순서에 맞게 도착하였으며, 해당 시퀀스 번호까지의 모든 데이터는 이미 확인 응답되었을 경우 -> ACK를 지연시켜 추가적인 세그먼트 도착을 기다린다. 500ms까지 대기하며 그 이내에 다음 세그먼트가 도착하지 않으면 ACK를 전송한다.
- 만약 수신자가 예상한 순서에 따라 데이터 세그먼트를 받았다면 수신자는 누적 ACK(cumulative ACK)을 발송한다.
- 예상 시퀀스 번호보다 높은 값으로 도착한 비순서 세그먼트가 감지되었을 때 -> 즉시 중복된 ACK을 전송하여 어느 바이트부터 기대하는지 알려준다.
TCP fast retransmit
TCP Fast Retransmit은 TCP 프로토콜의 한 기능으로, 데이터 전송 중에 발생한 패킷 손실을 감지하고 복구하는 방법이다. 이 기능은 "triple duplicate ACKs"라는 현상을 기반으로 동작한다.
"Triple duplicate ACKs"란, 송신자가 동일한 데이터에 대해 3개의 중복 ACK를 추가로 수신한 경우를 의미한다. 즉, 총 4번의 동일한 ACK을 응답받아야 한다.
TCP Fast Retransmit은 이러한 "triple duplicate ACKs"를 수신하면, 재전송 대기 시간인 타임아웃(timeout)을 기다리지 않고 즉시 손실된 세그먼트를 재전송한다. 왜냐하면 "triple duplicate ACKs"를 수신한 것은 이미 손실된 세그먼트 이후의 세그먼트들이 정상적으로 도착했음을 의미하기 때문에, 손실된 세그먼트를 복구하기 위해 추가적인 대기 시간을 기다리는 것은 비효율적이다.
따라서, TCP Fast Retransmit은 손실된 세그먼트를 빠르게 재전송하여 데이터 전송의 효율성을 향상시킨다. 이 기능은 네트워크의 혼잡 상황을 해소하고 전송 속도를 최적화하기 위해 사용된다.
TCP flow control
TCP 흐름 제어는 네트워크 계층이 데이터를 전송하는 속도가 애플리케이션 계층이 소켓 버퍼에서 데이터를 제거하는 속도보다 빠른 경우를 다루는 메커니즘이다.
만약 네트워크 계층이 데이터를 너무 빠르게 전송하면, 애플리케이션 계층이 데이터를 소켓 버퍼에서 제거하는 데 시간이 걸리므로, 버퍼가 오버플로우(overflow) 될 수 있다. 이를 방지하기 위해 TCP 흐름 제어는 수신자가 송신자의 데이터 전송 속도를 제어한다. 즉, 수신자는 송신자에게 너무 많은 데이터를 너무 빠르게 보내지 않도록 지시한다.
이렇게 흐름 제어를 사용하면, 수신자의 버퍼가 오버플로우 되는 것을 방지하고 데이터 전송의 안정성을 유지할 수 있다. 이는 네트워크의 효율성을 최적화하는 데 중요한 역할을 한다.
TCP 수신자는 TCP 헤더의 rwnd 필드를 통해 사용 가능한 버퍼 공간을 "광고"한다. rwnd는 수신 윈도우(Receive Window)를 나타내며, 수신자가 현재 수신하고 처리할 수 있는 데이터의 양을 나타낸다.
RcvBuffer 크기는 소켓 옵션을 통해 설정되며, 일반적인 기본값은 4096 바이트이다. 많은 운영 체제는 RcvBuffer를 자동으로 조정한다.
송신자는 수신한 rwnd 값으로 인해 확인되지 않은("비행 중인") 데이터의 양을 제한한다. 이는 수신 버퍼가 오버플로우되지 않도록 보장한다.
TCP 3-way handshake
데이터를 교환하기 전에, 송신자와 수신자는 "핸드셰이크"를 진행한다. 이는 연결을 설정하는 데 동의하고(서로 연결을 설정할 의사가 있다는 것을 알게 됨), 연결 파라미터(예: 시작 시퀀스 번호 등)에 대해 합의하는 과정이다.
이 핸드셰이크 과정은 TCP에서 3-way handshake라고 불리며, 다음과 같은 순서로 진행된다:
- 송신자는 SYN 패킷을 수신자에게 보내 연결을 요청한다. 이 패킷에는 송신자의 초기 시퀀스 번호가 포함된다.
- 수신자는 SYN 패킷을 받고, 자신의 초기 시퀀스 번호와 함께 SYN+ACK 패킷을 송신자에게 보낸다. 이는 연결 요청을 수락하고 동시에 자신의 연결 요청을 보내는 것을 의미한다.
- 송신자는 SYN+ACK 패킷을 받고, ACK 패킷을 수신자에게 보내 연결을 확인한다.
이렇게 3-way handshake를 통해 TCP 연결이 성립되며, 이후 데이터 교환을 시작할 수 있다. 이 과정을 통해 송신자와 수신자는 서로의 상태를 확인하고, 데이터 전송을 위한 준비를 마친다.
TCP 연결을 종료하는 과정은 클라이언트와 서버가 각각의 연결을 닫는 것으로 이루어진다. 이 과정은 다음과 같다:
- 연결을 종료하고자 하는 측이 FIN 비트가 1로 설정된 TCP 세그먼트를 보낸다. 이는 "더 이상 전송할 데이터가 없다"는 신호이다.
- FIN 패킷을 받은 측이 ACK를 보내, FIN 패킷을 수신했음을 확인한다.
- FIN 패킷을 받은 측이 아직 전송할 데이터가 남아 있다면, 그 데이터를 보내고 나서 자신의 FIN 패킷을 보낸다. 이때, ACK와 자신의 FIN을 함께 보낼 수 있다.
- 처음 FIN 패킷을 보낸 측이 상대방의 FIN을 ACK로 응답하며 연결 종료를 마무리한다.
이런 식으로 TCP 연결은 안정적으로 종료된다. 동시에 두 측이 FIN 패킷을 보내는 상황에서도 이 과정은 문제없이 처리된다.
Cogestion control principles
네트워크 혼잡은 네트워크에서 데이터 트래픽이 과도하게 증가하여 처리 용량을 초과할 때 발생하는 상황을 말한다. 이는 다수의 송신자가 너무 많은 데이터를 너무 빠르게 보내 네트워크가 처리할 수 없는 상태를 의미한다.
혼잡이 발생하면 다음과 같은 문제가 발생한다:
- 긴 지연 시간: 네트워크 내의 라우터나 스위치에서 데이터 패킷이 대기하게 되며, 이로 인해 전송 지연이 길어진다.
- 패킷 손실: 라우터나 스위치의 버퍼가 가득 차면 패킷을 더 이상 저장할 수 없어 패킷이 손실된다.
이렇게 혼잡이 발생하면 네트워크의 성능이 저하되고, 심한 경우에는 네트워크 연결이 끊기는 등의 문제가 발생할 수 있다.
가장 간단한 시나리오를 먼저 살펴보자. 한 라우터와 무한한 버퍼가 있으며, 입력과 출력 링크 용량은 R이다. 재전송은 필요하지 않으며, 두 개의 호스트가 패킷을 전송 중이다.
이때 입출력 링크 용량은 R이므로 한 연결 당 throughput은 최대 R/2까지 증가할 수 있다. 또한 패킷의 송신이 불규칙하기 때문에 delay는 기하급수적으로 증가하게 된다.
두 번째 시나리오에서는 유한한 버퍼를 가지고 송신자는 loss나 timeout 발생 시에 패킷을 재전송한다.
또한 loss로 인한 재전송과 timeout에 의한 불필요한 복제본의 재전송이 발생해 throughput에 손실이 생긴다.
이 경우 추가 전송으로 인해 애플리케이션 계층이 요청한 양보다 전송 계층이 전송한 데이터의 양이 더 많다.
세 번째 시나리오에서는 다음과 같이 4개의 송신자가 있는 상황을 생각해보자. 여기서 호스트 A, B만을 살펴보면 두 호스트가 전송한 패킷들은 모두 라우터 2를 지난다. 하지만 호스트 A의 패킷은 라우터 1을 지나기 때문에 라우터 2로의 도착률은 최대 R/2까지밖에 증가할 수 없다. 반면 호스트 B의 패킷은 라우터 2로 바로 전송되기 때문에 도착률은 무한대로 증가할 수 있다. 때문에 라우터 2에서는 호스트 A가 보낸 패킷이 매몰되는 현상이 발생할 수 있다.
이 경우 혼잡에 의해 버려지는 패킷들이 추가적으로 발생한다.
TCP Congestion control
TCP의 혼잡 제어는 인터넷 데이터 전송에 사용되는 TCP 프로토콜의 핵심적인 부분이다. 일반적으로 네트워크 혼잡제어는 종단 시스템에서 이루어진다. 혼잡제어 방식은 네트워크가 종단 시스템에 피드백을 주는가에 따라 End-to-end cognition control 과 Network-assisted cognition control로 나눠진다. End-to-end cognition control는 네트워크의 피드백을 받지 않고 end host가 증상들을 바탕으로 스스로 추론하는 방식으로 TCP에서 사용된다. 반면 Network-assisted cognition control는 라우터가 sender와 receiver에게 최소한의 정보를 제공하는 방식으로 TCP ECN에서 사용된다.
AIMD
Additive Increase/Multiplicative Decrease (AIMD) 접근법은 TCP 혼잡제어 과정에서 사용되는 주요 전략 중 하나이다.
AIMD 접근법에서 송신자들은 패킷 손실(혼잡)이 발생할 때까지 송신률을 점진적으로 증가시킨다. 이런 점진적인 증가를 "Additive Increase"라고 부르며, 일반적으로 매 라운드 트립 타임(RTT)마다 최대 세그먼트 크기(MSS) 1만큼 송신률을 증가시키는 것을 의미한다.
패킷 손실이 감지되면, 즉 네트워크 혼잡이 발생하면, 송신자는 혼잡을 완화하기 위해 송신률을 줄인다. 이런 감소를 "Multiplicative Decrease"라고 부르며, 일반적으로 각각의 패킷 손실 이벤트마다 송신률을 반으로 줄이는 것을 의미한다.
AIMD 방식의 결과로 시간에 따른 대역폭 사용 패턴은 톱니파 모양과 유사하게 나타난다: Additive Increase 단계 동안의 꾸준한 증가와 Multiplicative Decrease 단계에서의 급격한 감소. 이 패턴은 데이터 전송이 계속되는 한 반복된다.
TCP가 프로빙(probing)을 사용하여 가능한 대역폭 활용과 네트워크 혼잡 회피 사이에서 최적의 균형점을 찾으려고 하는 방식도 보여준다. TCP는 패킷 로스와 같은 네트워크로부터 받아오는 피드백에 기반하여 그 자체를 보내기 위한 비율 조절함으로써 변화하는 조건에 맞게 수정할 수 있다.
따라서 모든 사용자들에게 공정하게 대역폭 분배를 하면서도 어느 한 사용자가 과도하게 대역폭을 차지하여 전체 네트워크 성능이 저하되는 것을 방지할 수 있다.
일반적으로 혼잡의 증상에는 timeout과 3 duplicate ack이 있다. 이 중 더 심각한 문제로 여겨지는 것은 timeout 문제이다. 3 duplicate ack의 경우 하나의 패킷만 전송 실패이고 뒤에 오는 나머지 패킷은 성공적으로 전송되었다는 것을 알 수 있지만, timeout의 경우 그에 대한 피드백이 없기 때문이다. TCP Tahoe와 TCP Reno는 혼잡 증상에 따라 다른 동작방식을 갖는다. TCP Tahoe의 경우 두 증상을 구분하지 않고, 어떠한 경우에도 multiplicative decrese를 1부터 시작한다. 반면 TCP Reno의 경우 timeout이 발생했을 때는 1부터, 3 duplicate ack이 발생했을 때는 절반으로 줄인다.
Cognition window
cwnd(Cognition window)는 송신자가 수신자의 허락없이 보낼 수 있는 최대 데이터의 양을 뜻한다.
이때 보냈으나 아직 ACK이 오지 않은 데이터의 양(in-flight)은 cwnd를 초과하지 않는다.
TCP 송신 비율은 cwnd에 RTT를 나눈 값으로 1segment는 1400byte에 해당한다.
송신자는 혼잡을 감지하면 window를 줄이고 없으면 최대한 키운다.
TCP slow start
TCP slow start 방식은 처음 전송 시에 cwnd를 1 MSS로 설정하고 전송이 성공하면 cwnd를 2배씩 늘리는 방식이다. 결과적으로 초기 전송률은 느리지만 점차 기하급수적으로 증가한다.
전송률은 2배씩 증가하다가 ssthresh라는 지점에 도달하면 다시금 1씩 선형적으로 증가한다. 이후 혼잡 발생시 ssthresh는 혼잡 발생 시점 congestion window의 절반으로 설정된다. 동시에 혼잡 증상에 따라 multiplicative decrese가 진행된다.
아래는 혼잡제어 과정을 나타낸 것이다.
TCP CUBIC
TCP slow start 방식의 경우 전송률이 충분히 증가하기까지 시간이 오래 걸린다는 단점이 있다. 이에 TCP CUBIC은 최대 전송률로 추정되는 지점에 멀수록 빠르게 증가하다가 그 근방에서는 조심스럽게 증가시키는 방식을 채택했다.
만약 최대 전송률로 추정되는 지점 K를 지났음에도 혼잡이 발생하지 않는다면 다시금 전송률을 급속도로 증가시킨다. (K에 가까울수록 느리게, 멀수록 빠르게 증가시키므로)
TCP 전송률은 다음과 같이 설정된다.
TCP CUBIC은 주로 Linux에서 사용되며 multiplicative decrese는 TCP Reno를 따른다.
Delay-based TCP congestion control(TCP Vegas)
TCP는 혼잡이 발생할 때까지 전송률을 증가시킨다. 이때 패킷 손실이 가장 먼저 일어나는 곳을 '혼잡 병목 링크'라고 한다.
이런 혼잡의 빈도를 줄이기 위해 delay-based control 방식을 사용한다. 이는 혼잡이 발생하지 않을 때의 RTT인 RTT_min을 측정하고, cwnd/RTT_min으로 uncongested throughput을 구한다. 그 후 현재의 cwnd와 RTT를 통해 현재의 throughput을 측정해 uncongested throughput과 비교한다. 만약 현재 throughput이 uncongested throughput에 가깝다면 여유가 있는 상태라고 판단하여 cwnd를 늘리고, 반대로 멀다면 혼잡에 가까워진 상태라고 판단하여 cwnd를 줄인다. 이 방식을 사용하면 혼잡에 도달하지 않고 혼잡을 미연에 방지할 수 있다.
구글은 BBR이라는 자체 알고리즘을 만들어 사용하고 있다.
Explicit congestion notification(ECN)
ECN은 송수신자가 네트워크에게 혼잡 정보를 얻는 Network-assisted cognition control 방식이다.
ECN은 라우터가 네트워크 혼잡을 감지하면 IP 헤더의 ECN 필드에 특정 비트를 설정하여 혼잡을 명시적으로 표시하는 방식을 사용한다. 이 혼잡 표시는 목적지까지 패킷과 함께 전달되며, 목적지에서는 이를 감지하고 TCP ACK 패킷의 ECE(Explicit Congestion Experienced) 비트를 설정하여 송신자에게 혼잡을 알린다. 송신자는 이 ECE 비트를 감지하면 혼잡을 인지하고, 혼잡 제어 알고리즘을 적용하여 데이터 전송률을 줄이게 된다.
이렇게 함으로써 ECN은 패킷 손실을 미리 예방하고, 실제 패킷 손실이 발생하기 전에 혼잡을 관리할 수 있게 해준다.
TCP fairness
여러 TCP connection이 공평한 전송률을 가질 수 있는가에 대한 물음에 대해 동일한 RTT와 혼잡이 없는 고정 세션을 갖는 한 그렇다고 대답할 수 있을 것이다.
용량이 R인 라우터를 공유하는 두 개의 TCP connection이 있을 때 각 throughput은 AIMD에 따라 다음 그림과 같은 전송률의 변화를 보인다. 결과적으로 두 connection의 전송률은 서로 같아지도록 수렴하게 된다.
하지만 UDP의 경우 혼잡 제어 알고리즘이 존재하지 않기 때문에 TCP보다 더 많은 자원을 사용해 공정성에 문제를 일으킬 수 있다. 또한 한 호스트가 여러 개의 TCP connection을 갖는 경우도 공정성에 위배되는 것이라 볼 수 있다.
QUIC
TCP와 UDP와 같은 transport protocol들이 존재 함에도 여전히 여러가지 문제들이 산재되어 있다. 예를 들어, 무선 네트워크 사용시에는 채널이 불안정하므로 bitt error가 발생할 수 있다. 이때 TCP sender는 이를 혼잡의 증상으로 생각하고 cwnd를 줄일 수 있다는 문제가 있다. 이런 특정 시나리오들을 해결하기 위한 여러가지 해법들이 제시되었는데 QUIC도 이중 하나이다.
QUIC는 TCP의 신뢰성과 순서를 유지하는 기능을 유지하면서, UDP의 간결성과 유연성을 활용한다. 이를 위해 transport 계층에서 UDP를 쓰되, application 계층에 QUIC를 추가하여 신뢰성과 순서를 보장한다.
'학교공부 > 컴퓨터 네트워크' 카테고리의 다른 글
Network Layer: Control Plane (0) | 2023.12.02 |
---|---|
Network Layer: Data Plane (0) | 2023.11.29 |
[컴퓨터 네트워크] Computer Network outline (0) | 2023.10.21 |
[컴퓨터 네트워크] Application Layer (0) | 2023.10.11 |