TCP/IP 흐름제어 & 오류제어

HunkiKim·2022년 9월 3일
0
post-custom-banner

TCP/IP 흐름제어 & 오류제어

트랜스포트 계층 서비스

먼저 이를 알기 전에 트랜스포트 계층 서비스에 대해 간단하게 말하고자 한다. 트랜스포트 계층 프로토콜은 서로 다른 호스트에서 동작하는 애플리케이션 프로세스들 간의 논리적 통신(logical communication)을 제공한다. 논리적 통신은 애플리케이션의 관점에서 보면 프로세스들이 동작하는 호스트들이 직접 연결된 것처럼 보인다는 것을 의미한다. 실제로 호스트는 수많은 라우터와 다양한 형태의 링크를 통해 연결된다.

이 계층은 종단 시스템에서 구현되며 애플리케이션 프로세스로부터 수신한 메시지를 세그먼트(segment)인 트랜스포트 계층 패킷으로 변환한다.

네트워크 계층과의 관계는 우편부를 항상 예로 들수 있다. 사촌형제들이 있는 집의 편지들을 모아주는 앤,빌과 편지를 전달하는 우편부가 있다고 하자. 먼저 봉투 안의 편지는 애플리케이션 메시지, 프로세스는 사촌 형제들, 호스트(종단 시스템)은 집, 트랜스포트 계층 프롴토콜은 앤과 빌, 네트워크 계층 프로토콜은 우편 서비스이다.
사촌 형제들이 메시지를 보내기위해 메시지를 쓰고 봉투안에 싸서 앤과 빌한테 전해준다. 앤과 빌은 이를 잘 모아서 우편서비스를 통해 다른 집들과 통신한다. 이것을 보면 네트워크 계층은 종단 시스템끼리의 통신을 의미한다. 그리고 트랜스포트 계층은 프로세스들과의 통신을 한다. 즉 집 내부에서 통신을 하는 것이다. 앤과 빌은 집에 일부이지만 사촌형제들은 앤과 빌이 논리 통신을 제공한다.

만약 여기서 앤과 빌 없이 편지를 전달하면? 전문적이지 않기 때문에 편지가 없어지고, 다른사람에게 전달되거나 하는 문제가 발생할 수 있다. 하지면 여기서 알 수 있는점은 개별 프로토콜은 만들 수있다는 점이다. 정리하면 트랜스포트 프로토콜은 애플리케이션 프로세스에서 네트워크 계층까지 메시지를 운반하고, 반대 방향으로 네트워크 계층에서 애플리케이션 계층으로 메시지를 운반한다. 중간 통로와 같은 역할이라고 볼 수 있다.

TCP/IP 네트워크는 애플리케이션 계층에게 두 가지 구별되는 트랜스포트 계층 프로토콜을 제공한다. 비신뢰, 비연결형 UDP(User Datagram Protocol)와, 신뢰,연결지향 TCP(Transmission Control Protocol)이다. 일단 오늘은 TCP와 흐름제어, 혼잡제어에 대해서 정리하려 한다.

다중화, 역다중화

간단하게 말하면 호스트-호스트 전달을 프로세스-프로세스 전달로 확장하는 것을 트랜스포트 다중화(transport multiplexing)와 역다중화(demultiplexing)라고 한다. 이는 모든 컴퓨터 네트워크에서 필요한 것이다. 프로세스는 소켓을 통해 데이터를 전달하고 받을 수 있다. 여기서 트랜스포트 계층 세그먼트의 데이터를 올바른 소켓으로 전달하는 작업을 역다중화라고 한다. 출발지 호스트에서 소켓으로부터 데이터를 모으고, 이에 대한 세그먼트를 생성하기 위해 각 데이터에 헤더 정보로 캡슐화하고, 그 세그먼트들을 네트워크 계층으로 전달하는 작업을 다중화라고한다.

TCP

TCP 특징?

TCP(Transmission Control Protocol)이란 트랜스포트 계층에서 사용되는 프로토콜이다. TCP는 두 프로세스가 핸드셰이크를 해야하므로 연결지향형(connection-oriented)이다. TCP 프로토콜은 오직 종단 시스템에서만 동작하고 중간의 네트워크 요소(라우터와 브릿지)에서는 동작하지 않으므로, 중간의 네트워크 요소들은 TCP 연결 상태를 유지하지 않는다. 중간의 라우터들은 전혀 TCP연결을 감지하지 못한다. 연결은 보지않고 데이터그램만 보기 때문이다.

또한 전이중(full-duplex) 서비스를 제공한다.또한 TCP연결은 점대점이다. 즉 1:1이라는 것이다.

TCP는 3-Way-Handshaking의 연결 절차를 가진다. 클라이언트가 특별한 세그먼트를 보내고 서버가 TCP 세그먼트로 응답한다. 마지막으로 다시 클라이언트가 특별한 세그먼트를 보내는 방식이다. 또한 4-way-Handshaking방식의 연결 해제 절차를 가진다.클라이언트가 종료신호를 보내고 서버가 확인, 그리고 서버가 종료신호를 보내고 클라이언트가 확인하는 4번의 전송이 거쳐진다.

TCP 세그먼트의 구조

TCP 세그먼트는 헤더 필드와 데이터 필드로 구성되어 있다. 32bit단위로 되어있다.

  • 상위 계층 애플리케이션으로부터 다중화와 역다중화를 하는 데 사용하는 출발지와 목적지 포트 번호가 있다.(16,16) IP는 네트워크 계층에서 다루기 때문에 포트번호만 있다.
  • 또한 UDP처럼 헤더는 체크섬 필드를 포함한다.
  • 신뢰적인 데이터 전송 서비스 구현에서 TCP 송신자,수신자에 의해 사용되는 순서번호 필드(sequence number field,32bit)와 확인응답번호 필드(knowledgement number field,32bit)가 있다.
  • 수신 윈도우(receive window, 16bit)필드는 흐름제어에 사용된다. 이는 수신자가 받아들이려는 바이트의 크기를 나타내는데 사용된다.
  • 헤더 길이(header length,4 bit)는 32bit 워드 단위로 TCP 헤더의 길이를 나타낸다.
  • 옵션(option)필드는 가변적이고 선택적이며 송신자와 수신자가 MSS를 협상하거나 고속 네트워크에서 사용하기 위한 윈도우 확장 요소로 사용된다. 타임스탬프 옵션 또한 정의된다.
  • 플래그(flag,6bit)도 포함한다. 하지만 현재 혼잡 제어 기능의 향상을 위해 Reserved필드를 사용해 NS,CWR,ECE 플래그를 추가한 9비트로 운영중이다.
  • 긴급 데이터 포인터 필드(urgent data pointer field,16bit)는 긴급 데이터 존재할때 사용된다.
  • Reserved 필드(미사용 필드)는 혹시모를 필드로 그냥 0이다.

여기서 가장 중요한 필드 두 가지는 순서번호 필드(Sequence number)와 확인응답 번호필드(Acknowledge Number)이다. TCP가 신뢰적인 데이터 전송 서비스를 하는데 중요한 부분이다. 세그먼트에 대한 순서번호는 세그먼트에 첫 번째 바이트의 바이트-스트림 번호이다. 메모리의 주소같은 느낌으로 생각하면된다. 세그먼테이션 분할방식에서 리미트와 첫주소?

그리고 확인응답 번호는 호스트 A가 호스트 B로부터 기대하는 다음 바이트의 순서 번호이다. 이는 진행되면서 다음 바이트를 어떤 바이트로 받을지에 대한 정보이다. 예를들어 0~535까지 번호가 붙은 모든 바이트를 수신했을때 확인응답 번호 필드에 536을 삽입하고 그것을 B헤 전달한다. 하지만 실제로 데이터를 주고 받을 떄는 상대방이 보낸 확인응답 번호 + 자신이 받은 데이터의 bytes로 번호를 만들어낸다.

신뢰적인 데이터 전달(reliable data transfer service)

TCP는 IP의 비신뢰적인 최선형 서비스에서 신뢰적인 데이터 전달 서비스를 제공한다. 이는 프로세스가 자신의 수신 버퍼로부터 읽은 데이터 스트림이 손상되지 않았으며 손실이나 중복이 없다는 것과 순서가 유지된다는 것을 보장한다. 다시 말해서, 바이트 스트림은 송신자가 전송한 것과 같은 바이트스트림이다.

흐름제어

TCP 연결이 순서대로 올바르게 바이트를 수신할 때, TCP는 데이터를 수신 버퍼에 저장한다. 프로세스는 버퍼에서 데이터를 읽지만 데이터가 도달한 시점에서 읽어야 할 필요는 없다. 하지만 이렇게 계속 수신자가 느리게 읽고 송신자가 데이터를 계속 보내면 오버플로를 발생시킨다. 이러한 오버플로를 방지하기 위해 흐름제어 서비스(flow-control service)를 제공한다.

이는 간단하게 말하면 읽는 속도와 전송 속도를 같게 하는 것이다. TCP 송신자는 IP네트워크에서 혼잡때문에 억제될 수 있다. 즉, 송신자 제어의 이 형태는 혼잡제어(congestion conrol)로 알려져 있다. 흐름제어와 혼잡제어에서 수행되는 동작들이 비슷하지만(송신자의 억제), 흐름제와 혼잡제어는 명백히 다른 목적을 위해 수행된다. 먼저 흐름제어 부터 보자.

TCP는 예전에는 Stop and wait방식이 있었지만 너무나도 비효율 적인 방식으로 인해 현재는 쓰지않는다. 매번 전송한 패킷에 대해 확인 응답을 받아야만 그 다음 패킷을 전송하는 방법이다. 그래서 생긴 것이 Sliding Windwo 방식이며 이는 수신측에서 설정한 윈도우 크기만큼 송신측에서 확인 응답 없이 세그먼트를 전송할 수 있게하여 데이터 흐름을 동적으로 조절하는 방식이다. 송신자가 수신 윈도우(receive window)라는 변수를 유지하며 흐름제어를 제공한다. 수신 윈도우는 수신 측에서 가용한 버퍼 공간이 얼마나 되는지를 송신자에게 알려 주는 데 사용된다. TCP는 전이중이므로 각 측의 송신자는 별개의 수신 윈도우를 유지한다.

다음은 호스트 A가 호스트 B에게 큰 파일을 전송한다고 가정할 때, 호스트 B는 이 연결에 수신 버퍼를 할당한다.
아래는 B의 변수들이다.

다음과 같은 변수를 정의해야한다.

  • LastByteRead : 호스트 B의 애플리케이션 프로세스에 의해 버퍼로부터 읽힌 데이터 스트림의 마지막 바이트의 수
  • LastByteRcvd : 호스트 B의 수신 버퍼에 저장된 데이터 스트림의 마지막 바이트수
  • RcvBuffer : 호스트 B의 할당된 수신 버퍼의 크기
  • rwnd : 버퍼의 여유 공간.

rwnd = RcvBuffer - [LastByteRcvd-LastByteRead]
rwnd는 시간마다 변하기 때문에 동적이다.

호스트 B는 호스트 B가 호스트 A에게 전송하는 모든 세그먼트 윈도우 필드에 현재의 rwnd값을 설정함으로 연결 버퍼에 얼만큼 여유 공간이 있는지 호스트 A에게 알려준다. 초기값은 rwnd=RcvBuffer이다. 즉 간단하게 정리하면 rwnd는 전체 버퍼에서 송신자에게 받은 바이트 크기에서 읽힌 바이트만큼 뺀 나머지이다.

반면 호스트 A는 두 변수 LastByteSent와 LastByteAcked가 있다. 그리고 이 두 변수의 차이는 호스트 A가 이 연결에 전송 확인응답이 안 된 데이터의 양이다. rwnd의 값보다 작은 확인응답 안 된 데이터의 양을 유지함으로써 호스트 A는 호스트 B의 수신 버퍼에 오버플로가 발생하지 않는다는 것을 확신한다.

  • LastBySent-LastByteAcked<=rwnd

한마디로 확인응답 안 된 데이터의 양은 항상 여유공간보다 작아야 한다.

하지만 한 가지 문제가 생긴다. rwnd=0으로 가득 찼다고 해보자. 호스트 A에게 이를 알린후 호스트B는 호스트 A에게 전달할게 없다고 가정하면 호스트 B에서 애플리케이션 프로세스가 버퍼를 비우더라도, TCP는 호스트 A에게 새로운 rwnd로 새로운 세그먼트를 제공하지 않는다. TCP는 전송할 데이터가 있거나 전생해야 할 확인응답을 가진 경우에만 A에게 세그먼트를 전송하기 때문에, A는 B의 수신버퍼에 공간이 있는것을 알지 못한다. 이러면 A는 차단된다. 때문에 A가 B의 수신 윈도우가 0일때, 1바이트 데이터로 세그먼트를 계속해서 전송하도록 요구한다.

혼잡제어

혼잡제어는 송신측의 데이터 전달과 네트워크의 데이터 처리 속도를 해결하기 위한 기법이다. 아까의 흐름 제어는 송신측과 수신측의 데이터 처리 속도의 차이 떄문에 발생하였다면 혼잡제어는 송신측의 데이터 전달과 네트워크의 데이터 처리 속도를 해결하기 위한 기법이다. 즉 네트워크 내에 패킷의 수가 과도하게 증가하는 현상이 일어날때 제어하는것을 말한다.

예를들어 한 라우터에 데이터가 몰릴경우, 자신에게 온 데이터를 모두 처리할 수 없게 된다. 이런 경우 호스트들은 재전송을 하게되고 계속 혼잡을 가중시켜 오버플로우나 데이터손실을 발생시키게 된다. 그리고 네트워크 내에 패킷의 수가 과도하게 증가하는 현상을 혼잡이라 하며, 이를 제거하는게 혼잡제어이다.

TCP가 취한 접근방법은 네트워크 혼잡에 따라 연결에 보내는 트래픽을 보내는 전송률을 각 송신자가 제한하도록 하는것이다. 즉 송신측에서 보내는 데이터의 속도를 강제로 줄이는 것이다. TCP 혼잡제어 매커니즘은 추가적인 변수인 혼잡 윈도우(congestion window)를 기록한다. cwnd로 표시되는 혼잡 윈도우는 TCP 송신자가 네트워크로 트래픽을 전송할 수 있는 비율을 제한하도록 한다. 특히 송신하는 쪽에서 확인응답이 안 된 데이터의 양은 cwnd와 rwnd의 최솟값을 초과하지 않도록 한다.

그러면 어떻게 송신자가 자신의 송신 속도를 결정할까?
1. 손실된 세그먼트는 혼잡을 의미하며, 이에 따라 TCP 전송률은 한 세그먼트를 손실했을 때 줄어져야한다.
2. 확인응답된 세그먼트는 네트워크가 송신자의 세그먼트를 수신자에게 전송된다는 것이고, 이에 따라 이전에 확인응답되지 않은 세그먼트에 대해 ACK가 도착하면, 송신자의 전송률은 증가할 수 있다.
3. 밴드폭 탐색. 이것은 느린 시작과 같은데 혼잡이 발생할때까지 천천히 늘려나가고 발생 시점부터 줄여나가고 하는 탐색을 시작한다. 이러한 탐색 기반으로 결정하는 방법이다.

혼잡 제어 알고리즘에는 세 가지 방법이 있다. 슬로 스타트(slow start), 혼잡 회피(congestion avoidance), 빠른 회복(fast recovery)이다. 그리고 종종 가법적 증가, 승법적 감소(additive-increase, multiplicative decrease, AIMD)의 혼잡제어 형식이 있다.빠른 회복이 권고되지만 필수는 아니다.

AIMD

톱니형식의 그래프가 형성되는 혼잡제어 형식이다. 또한 밴드폭에 대한 TCP 탐색의 초기 직관을 보여준다. 즉 패킷이 문제없이 도착하면 Window Size를 1씩 증가시키며 전송한다. 이를 addictive increase라고 한다. 그리고 만약, 패킷 전송을 실패하거나 TIME_OUT이 발생하면 Window Size를 절반으로 감소시킨다. 나중에 진입하는쪽이 불리하지만 시간이 지날수록 공평하게 수렴한다. 초기엔 높은 대역폭을 사용하지 못하는 단점이 있다. 이는 슬로스타트와 동일하다.

Slow Start

AIMD는 초기 전송속도를 올리는 데 너무 시간이 오래걸린다. 그래서 시작은 똑같이 cwnd=1mss로 초기화를 하돼, 증가시킬때 1씩 증가하는 것이 아닌 지수적(2배)씩 증가시킨다. 만약 첫번째로 타임아웃에 의한 손실 이벤트가 있다면, TCP 송신자는 cwnd값을 1로 하고, 새로운 슬로 스타트를 시작한다. 또한 두 번째 상태변수인 ssthresh(slow start threshold) 값을 cwnd/2로 정한다.ssthresh의 초기 값은 OS가 디폴트로 지정한다. 두 번째로, 슬로 스타트가 끝나는 방법은 ssthresh와 연관된다. 계속 두배로 하는 것은 멍청한 방법이다. 그러므로 cwnd값이 ssthresh과 같으면, 슬로 스타느는 종료되고 TCP는 혼잡 회피 모드로 간다. 혼잡 회피는 조금더 조심스럽게 cwnd를 증가시킨다. 그리고 마지막으로 종료되는 조건은 3개의 중복 ACK들이 검출 되면, TCP는 빠른 재전송을 수행하여 회복 상태로 들어간다. window사이즈는 1씩 늘려준다.

혼잡 회피 모드로 들어가면 매 RTT마다 cwnd값을 두 배로 하기 보다는 RTT마다 하나의 MSS만큼 cwnd값을 증가시킨다. 혼잡 회피의 선형 증가는 TCP 타임아웃이 발생했을 때와 같이 동작한다. 슬로 스타트의 경우와 같이 , cwnd값을 1로 하고, ssthresh의 값은 손실 이벤트가 발생할 때의 cwnd 값의 반으로 설정한다. 하나의 혼잡이 3개의 중복된 ACK 이벤트의 의해 야기된다는 것을 상기하자. TCP는 cwnd의 값을 반으로 하고 ssthresh 값을 3개의 중복 ACK들을 수신한 시점에서의 cwnd값의 반으로 한다.

Fast Recovery

빠른 회복에서 cwnd값은 잃었던 세그먼트(TCP를 빠른 회복 상태로 들어가게 한 세그먼트)에 대한 매 중복된 ACK를 수신할 때마다 1MSS씩 증가시킨다. 타임아웃 이벤트 발생시 빠른 회복은 슬로 스타트와 혼잡 회피에서와 같은 동작 시행후 슬로 스타트로 전이한다. 즉 , cwnd -> 1MSS , ssthresh -> cwnd/2
필수는 아니지만 권고사항이다.

Fast Restrasmit

빠른 재전송은 TCP 혼잡 조절에 추가된 정책이다. 패킷을 받는 쪽에서 도착해야할 패킷이 도착하지 않고 다음 패킷이 도착한 경우에도 ACK 패킷을 보내게된다. 단, 순서대로 잘 도착한 마지막 패킷의 다음 패킷의 순번을 ACK 패킷에 실어서 보내게 되므로, 중간에 하나가 손실되게 되면 송신 측에선 순번이 중복된 ACK 패킷을 받게 된다. 이것을 감지하면 바로 순번의 패킷을 재전송하게 해준다. 중복된 순번의 패킷을 3개 받으면 재전송을 하게 된다. 약간 혼잡한 상황이 일어난 것이므로 혼잡을 감지하고 window size를 줄이게 된다.

즉 손실된게 3번 중복으로 오면 즉시 손실된 패킷을 재전송 해주는 것이다.

TCP Tahoe vs TCP Reno

Tahoe -> loss를 무조건 timeout으로 처리 즉, loss발생할 때마다 cwnd=1로 변경
Reno -> loss를 3 duplicate ACKS 또는 timeout으로 처리. 현재는 Reno가 보통으로 사용된다. loss가 타임아웃이면 같지만 3중복ACKS라면 1로떨어지는 것이 아닌 1/2로 떨어진다. 따라서 빠른 회복(Fast Recovery)라고 부른다.

post-custom-banner

0개의 댓글