Post

Transport Layer

트랜스포트 계층 서비스 및 개요



트랜스포트 계층 프로토콜은 서로 다른 호스트에서 동작하는 애플리케이션 프로세스들 간의 논리적 통신(logical communication) 을 제공함.

논리적 통신은 애플리케이션 관점에서 보면 프로세스들이 동작하는 호스트들이 직접 연결된 것처럼 보인다는 것을 의미함.

애플리케이션 프로세스는 메시지 운반에 사용되는 물리적인 하위 구조의 세부 사항에 상관없이 서로 메시지를 송신하기 위해서 트랜스포트 계층에서 제공하는 논리적 통신을 사용.


트랜스포트 계층 프로토콜은 네트워크 라우터가 아닌 end system에서 구현됨.

송신 측의 트랜스포트 계층은 송신 애플리케이션 프로세스로부터 수신한 메시지를 세그먼트(트랜스포트 계층 패킷)으로 변환함.

이런 변환은 애플리케이션 메시지를 세그먼트로 만들기 위해 작은 조각으로 분할하고, 각각의 조각에 트랜스포트 계층 헤더를 추가함으로서 수행됨.

그 후 트랜스포트 계층은 송신 end system에 있는 네트워크 계층으로 세그먼트를 전달하고, 여기서 세그먼트가 데이터그램(네트워크 계층 패킷) 안에 캡슐화되어 목적지로 전달됨.

네트워크 라우터는 오로지 데이터그램의 네트워크 계층 필드에 대해 동작하는 것을 유의해야 함.
즉, 라우터는 캡슐화된 트랜스포트 계층 세그먼트의 필드를 검사하지 않음)


수신 측에서 네트워크 계층은 데이터그램에서 트랜스포트 계층 세그먼트를 추출하고(디캡슐화) 트랜스포트 계층으로 세그먼트를 보냄.

이후 트랜스포트 계층은 수신 애플리케이션에서 세그먼트 내부의 데이터를 이용할 수 있도록 수신된 세그먼트를 처리함.


네트워크 애플리케이션은 하나 이상의 트랜스포트 계층 프로토콜이 사용 가능함.

대표적으로 인터넷은 TCP, UDP라는 두 가지 트랜스포트 계층 프로토콜을 가지고 있음.



트랜스포트 계층과 네트워크 계층 사이의 관계



트랜스포트 계층 프로토콜은 서로 다른 호스트에서 동작하는 프로세스들 사이의 논리적 통신 제공하지만, 네트워크 계층 프로토콜은 호스트들 사이의 논리적 통신 제공.

미묘하지만 이런 차이점은 중요함.

트랜스포트 계층 프로토콜들은 end system안에서 애플리케이션 프로세스에서 네트워크 경계(네트워크 계층)까지 메시지를 운반함. (또한 반대 방향으로도 운반, 네트워크 계층 -> 앱 프로세스)

그러나 메시지가 네트워크 계층 내부에서 어떻게 이동되는지는 언급하지 않음.

즉, 중간 라우터는 트랜스포트 계층이 애플리케이션 메시지에 추가한 어떤 정보도 인식 X, 그 정보에 영향 X


트랜스포트 계층이 제공할 수 있는 서비스는 하위 네트워크 계층의 서비스 모델에 따라 제약됨.

만약 네트워크 계층 프로토콜이 호스트 사이에서 전송되는 트랜스포트 계층 세그먼트에 대한 지연 보장이나 대역폭 보장을 제공하지 못하면, 트랜스포트 계층 또한 이러한 서비스를 제공해줄 수 없음.


그럼에도 불구하고 특정 서비스는 트랜스포트 프로토콜에 의해서 제공될 수 있음.

예를 들어, 하위 네트워크 프로토콜이 비신뢰적일 때(패킷 분실 또는 손실, 복사본 생성 등)에도 애플리케이션에게 신뢰적인 데이터 전송 서비스를 제공 가능함.

트랜스포트 프로토콜(TCP, UDP)은 네트워크 계층이 트랜스포트 계층 세그먼트의 기밀성을 보장할 수 없을 때도 침입자가 애플리케이션 메시지를 읽지 못하도록 암호화(보안 서비스)를 사용할 수 있음.



인터넷 트랜스포트 계층의 개요



인터넷의 네트워크 계층 프로토콜은 인터넷 프로토콜(Internet Protocol), 줄여서 IP

IP 서비스 모델은 호스트들 간에 논리적 통신을 제공하는 최선형 전달 서비스(best effort delivery service)임.


즉, IP는 통신하는 호스트 간 세그먼트 전달에는 최선을 다하지만, 손실이나 순서 등 어떠한 보장도 하지 않는다는 것.

또한 무결성도 제공하지 않아 비신뢰적인 서비스라고도 함.


UDP와 TCP의 가장 기본적인 기능은 호스트 간 IP 전달 서비스를 호스트에서 작동하는 두 프로세스 간의 전달 서비스로 확장하는 것.

트랜스포트 다중화(transport multiplexing)란, 호스트-호스트 전달프로세스-프로세스 전달 로 확장하는 것이며 그 반대를 역다중화(demultiplexing)라고 부름.


UDP가 제공하는 서비스는

  • 프로세스 대 프로세스 데이터 전달

  • 오류 검출


UDP는 비신뢰적인 서비스로 데이터의 무결성을 보장하지 않음.


TCP는 신뢰적인 데이터 전달을 제공함.

  • 흐름제어, 순서번호, 확인응답, 타이머를 사용해서 데이터가 순서대로 정확하게 전달되도록 보장.

  • 또한 혼잡제어를 사용함으로서 송신 측의 TCP가 네트워크에 보낼 수 있는 트래픽 양을 조절하여 혼잡한 네트워크 링크에서 각 TCP 연결이 링크의 대역폭을 공평하게 공유하여 통과하도록 함.






다중화와 역다중화



트랜스포트 계층 다중화와 역다중화


  • 프로세스는 소켓을 가지고 있으며 이를 통해 네트워크에서 프로세스(또는 그 반대)로 데이터를 전달함.

  • 각각의 소켓은 어떤 하나의 유일한 식별자를 가지며 TCP, UDP인지에 따라서 달라짐.

  • 세그먼트에는 필드 집합(목적지 포트 번호)이 있는데 이는 수신하는 소켓 식별을 위한 부분임.


  • 역다중화(de-multiplexing) : 트랜스포트 계층 세그먼트의 데이터를 올바른 소켓으로 전달하는 작업.

  • 다중화(multiplexing) : 소켓에서 세그먼트를 네트워크 계층으로 전달하는 작업.


다중화에는 두 가지 조건이 있음.

  1. 소켓은 유일한 식별자를 가진다.

  2. 각 세그먼트는 세그먼트가 전달될 적절한 소켓을 가리키는 특별한 필드(출발지, 목적지 포트 번호)를 가진다.


아래 사진은 트랜스포트 계층 세그먼트 필드임.

transport layer segment fields


역다중화 서비스가 구현되는 순서는 다음과 같음.

  1. 호스트의 각 소켓은 포트 번호를 할당 받는다.

  2. 세그먼트가 호스트에 도착하면, 트랜스포트 계층은 목적지 포트 번호를 검사, 상응하는 소켓으로 전송.

  3. 소켓을 통해 세그먼트는 해당 프로세스로 전달됨.


위의 과정은 UDP의 기본 동작 방식임.



비연결형(UDP) 다중화와 역다중화



비연결형 역다중화


비연결형 역다중화의 특징은 UDP 소켓이 목적지 IP주소목적지 포트 번호로 구성된 두 요소로 된 집합에 의해서 식별된다는 점임.

이러한 결과로, 만약 2개의 UDP 세그먼트들이 출발지 IP 주소와 출발지 포트 번호가 모두 다르거나 어느 한 가지가 다를지라도, 동일한 목적지 IP주소와 목적지 포트 번호를 가지면 2개의 세그먼트들은 같은 목적지 소켓을 통해 동일한 프로세스로 향하게 됨.
즉, UDP는 하나의 프로세스로만 세그먼트를 받는다는 것.



연결지향형(TCP) 다중화, 역다중화



TCP는 UDP와 달리 4개의 집합 요소가 있음.

  • 출발지 IP주소

  • 출발지 포트 번호

  • 목적지 IP주소

  • 목적지 포트 번호


UDP와 달리 TCP는 프로세스별로 소켓을 생성하여 받는다는 것.
다른 출발지 주소 또는 출발지 포트 번호를 가지고 도착하는 2개의 TCP 세그먼트는 2개의 다른 소켓으로 향하게 됨.
초기 연결 설정 요청을 전달하는 TCP는 제외함.


TCP 클라이언트-서버 프로그램은 다음과 같은 특징을 가짐.

  1. 서버 애플리케이션은 welcoming socket을 가짐. 초기 연결 설정 요청을 기다리는 소켓임.

  2. TCP 클라이언트는 소켓을 생성 후 연결 설정 요구 세그먼트를 보냄.

  3. 수신 호스트 os는 해당 프로세스를 찾으면 그 서버는 새로운 소켓을 생성.

  4. 서버는 연결요청 세그먼트의 네 가지 값을 주목함. ( 출발지/목적지 IP와 출발지/목적지 포트 번호 )



웹 서버와 TCP



image


각각의 연결에 따라서 새로운 프로세스 생성하지만 매번 일대일 대응을 하진 않음.

오늘날의 고성능 웹 서버들은 하나의 프로세스만 사용, 각각의 새 클라이언트 연결을 위해 새 연결 소켓과 함께 새로운 스레드 생성.

예를 들면, 웹 서버는 포트 번호 80만을 이용한 하나의 프로세스만 사용


웹 서버는 지속적인 HTTP를 사용함.

만약 비지속적일 경우에는 모든 요청/응답마다 새로운 TCP 연결이 생성/종료되며 새로운 소켓 생성 후 요청/응답 종료될 것임.

이 빈번하게 발생되는 소켓 생성과 종료는 웹 서버 성능에 심한 부담을 줄 것임.






비연결형 트랜스포트: UDP



UDP는 세그먼트를 송신하기 전에 송신 트랜스포트 계층 개채들과 수신 트랜스포트 계층 개체들 사이에 핸드셰이크를 사용하지 않는데, 이러한 이유로 비연결형이라고 함.

왜 애플리케이션 개발자가 TCP보다 UDP 방식으로 애플리케이션을 개발하는가 ?

UDP는 비신뢰적인, 비연결형 프로토콜이니까 TCP가 더 좋다고 생각할 수 있지만 아님.

아래와 같은 이유 때문에 많은 애플리케이션은 UDP에 더 적합함.


첫 번쨰로 무슨 데이터를 언제 보낼지에 대해 애플리케이션 레벨에서 UDP가 더 정교한 제어가 가능함.

UDP는 앱 프로세스가 데이터를 UDP에게 전달하자마자 UDP는 데이터를 세그먼트로 만들고 네트워크 계층으로 전달함.

그러나 TCP는 혼잡제어 메커니즘 때문에 바로 전송하지 못할수도 있음.

혼잡제어 메커니즘은 트래픽을 조절하는 기능도 있으며, 신뢰적인 데이터 전달 기능에 의해 전달 시간은 상관 없이 목적지가 세그먼트 수신 여부를 확인응답할 때 까지 재전송을 계속 할 것임.

실시간 애플리케이션은 종종 최소 전송률을 요구하고, 지나친 지연 전송을 원치 않으며, 조금의 데이터 손실 또한 허용할 수도 있으므로 TCP 서비스보단 UDP 서비스가 더 적합함.


두 번째로 연결 설정이 없음.

TCP는 3 ways handshake를 사용하는 반면 UDP는 예비동작 없이 바로 전송함.

즉, UDP는 연결 설정에 어떠한 지연도 없음. 이는 DNS가 왜 TCP보다는 UDP에서 동작하는지에 대한 이유임.

만일 DNS가 TCP에서 동작한다면 많이 늘려질 것임.


세 번째로 연결 상태가 없음.

TCP는 end system에서 연결 상태를 유지하는 반면, UDP는 유지하지 않고 기록하지 않음.

이 연결 상태는 수신 버퍼 및 송신 버퍼, 혼잡제어 파라미터, 순서번호, 응답번호를 포함함.

따라서 TCP보다 UDP가 더 많은 클라이언트를 수용할 수 있음.


네 번째로 작은 패킷 헤더 오버헤드임.

TCP는 세그먼트마다 20byte의 헤더 오버헤드를 갖지만, UDP는 단지 8바이트밖에 안됨.


아래 표는 인기 있는 인터넷 애플리케이션이 사용하는 트랜스포트 프로토콜의 목록임.

인기 있는 인터넷 애플리케이션가 그 하위 트랜스포트 프로토콜


데이터가 손실, 분실, 순서 보장 등이 필요한 신뢰적인 데이터 전송 서비스가 필요한 애플리케이션들은 TCP
전자메일, 원격 터미널 접속, 웹, TCP상의 파일 전송 등


그러나 많은 중요한 애플리케이션은 TCP보다 UDP에서 동작함.

예를 들면, UDP는 네트워크 관리 데이터를 전달하는데 사용됨.

네트워크 관리 애플리케이션은 네트워크가 혼잡한 상태에 있을 때 자주 동작해야 하므로 이런 경우 UDP가 TCP보다 더 좋음.

또한 DNS는 TCP의 연결 설정 지연을 피하기 위해 UDP를 사용함.


정리하면 신뢰적인 데이터 전송이 애플리케이션의 성능에 절대적으로 중요한 것만은 아님.

또한 실시간 애플리케이션(전화, 화상회의 등)은 TCP 혼잡제어가 나쁜 영향을 미침.

그래서 멀티미디어 애플리케이션 개발자는 그들의 애플리케이션을 TCP 대신 UDP에서 동작하도록 구현함.

그러나 패킷 손실률이 낮고, 보안적인 이유로 UDP 트래픽을 막는 일부 조직에서 TCP는 점점 더 스트리밍 매체 전송에 매력적인 프로토콜이 되고 있음.


UDP 세그먼트 구조에 대해 설명하기 전에 애플리케이션이 UDP를 사용할 때도 신뢰적인 데이터 전송이 가능함.

바로 애플리케이션 자체에서 신뢰성을 제공하는 것임.

구글의 크롬의 QUIC 프로토콜은 UDP사에서 애플리케이션 계층에 신뢰성을 구현하였음.

단, 애플리케이션 개발자가 오랜 시간 분주하게 디버깅을 하는 어려운 작업이긴 하지만 그럼에도 신뢰성을 애플리케이션에 직접 포함할 수 있음.

즉, 애플리케이션 프로세스들은 TCP의 혼잡제어 메커니즘에 의해서 전송률 억제를 강요당하지 않고도 신뢰적으로 통신할 수 있음.






UDP 세그먼트 구조



UDP_segment


image


  • UDP 헤더는 2바이트씩 구성된 4개의 필드(총 8바이트)를 가짐.

    • length : 헤더를 포함하는 UDP 세그먼트의 길이(바이트 단위)

    • checksum : 세그먼트에 오류가 발생했는지를 검사하기 위해 수신 호스트에 의해서 사용됨.



UDP 체크섬



UDP 체크섬은 오류 검출을 제공함.

즉, 체크섬은 세그먼트가 출발지로부터 목적지로 이동 했을 때, UDP 세그먼트 안의 비트에 대한 변경사항이 있는지 검사하는 것.

송신 측에서 UDP는 1) 세그먼트 안에 있는 모든 16비트 워드 단위로 더하고 이에 대하여 2) 다시 1의 보수를 수행하며, 덧셈 과정에서 발생하는 오버플로는 윤회식 자리올림(wrap around)함.


예를 들어, 3개의 16비트 워드가 있다고 가정.

1
2
3
0110011001100000
0101010101010101
1000111100001100


이들 16비트 워드에서 처음 2개의 워드 합은 다음과 같음.

1
2
3
4
0110011001100000
0101010101010101
----------------
1011101110110101


앞 계산의 합에 세 번째 워드를 더하면 다음과 같은 결과를 얻음.

1
2
3
4
5
6
7
1011101110110101
1000111100001100
----------------
10100101011000001 

==> 
윤회식 자리올림으로 [1] 0100101011000001 => 0100101011000001 + [1] = 0100101011000010


마지막 합은 오버플로가 있고 이를 윤회식 자리올림을 하였음.

이제 1의 보수를 수행해야 하는데, 1의 보수는 모든 0을 1로, 1을 0으로 변환하는 과정임.

따라서 합 0100101011000010의 1의 보수는 1011010100111101이고, 이것이 체크섬이 됨.


수신자는 체크섬을 포함한 4개의 모든 16비트 워드들을 더하여 만약 패킷에 어떤 오류도 있지 않다면, 수신자의 합은 1111111111111111이 될 것임.

만약 비트 중에 하나라도 0이 있다면 오류가 발생했음을 알 수 있음.






신뢰성 있는 데이터 전송의 원리



이 절에서는 일반적인 상황에서의 신뢰성 있는 데이터 전송 문제를 다룬다.

신뢰적인 데이터 전송을 구현하는 문제는 네트워킹에서 매우 중요하다.

신뢰적인 채널에서는 전송된 데이터가 손상되거나 손실되지 않고, 모든 데이터는 순서대로 전달된다.

이것은 TCP가 인터넷 애플리케이션에게 제공하는 서비스 모델이다.

아래 사진은 신뢰적인 데이터 전송 연구에 대한 프레임워크이다.


신뢰있는 데이터 전송


이 절에서는 점점 복잡해지는 하위 채널 모델을 고려하는 신뢰적인 데이터 전송 프로토콜을 점진적으로 개발해 나간다.

한 가지 가정해야 할 것은, 보내어진 패킷은 일부 손실될 수 있지만 보내어진 순서대로 전달될 것이라는 것이다.

즉, 하부 채널은 패킷의 순서를 바꾸지 않는다는 점을 가정한다.

또한 단방향 데이터 전송의 경우인 송신측으로부터 수신 측까지의 데이터 전송만을 고려한다.



신뢰적인 데이터 전달 프로토콜의 구축



완전히 신뢰적 데이터 전송 프로토콜에 도달하기 위해서 조금씩 더 복잡해지는 일련의 프로토콜을 알아갈 것이다.

rdt는 reliable data transfer이고, udt는 unreliable data transfer을 나타낸다.



rdt 1.0



rdt 1.0은 완벽하게 신뢰적인 채널 상에서의 신뢰적인 데이터 전송의 경우이다.

rdt 1.0은 송신자와 수신자에 대한 유한상태 머신(finite-state machine, FSM) 정리는 아래와 같다.


rdt 1.0


왼쪽의 FSM은 송신자의 동작을 정의하고 오른쪽은 수신자의 동작을 정의한다.

유의할 점은 송신자 수신자 각각에 대해서 분리된 FSM이 있다는 것이다.

송신자와 수신자 FSM은 각각 하나의 상태만을 가지고 있다.


송신측은 event에 의해 상위 계층으로부터 데이터를 받아들이고 (rdt_send(data)) action으로 데이터를 포함한 패킷을 생성 (make_pkt(data))하고 패킷을 채널로 송신한다. (udt_send(packet))


수신 측에선 rdt_rcv(packet) 이벤트에 의해 하위의 채널로부터 패킷을 수신하고, 액션으로 패킷에서 데이터를 추출한 후 (extract(packet,data)) 데이터를 상위 계층으로 전달한다. (deliver_data(data))


이런 간단한 프로토콜에서는 데이터 단위와 패킷 단위의 차이점이 없으며, 모든 패킷 흐름은 송신자로부터 수신자까지이다.

즉, 완전히 신뢰적인 채널에서는 오류가 생길 수 없으므로 수신 측이 송신 측에게 어떤 피드백도 제공할 필요가 없으며, 수신자는 송신자가 데이터를 송신하자마다 데이터를 수신할 수 있다고 가정했음에 유념해야 한다.



rdt 2.0



rdt 2.0은 비트 오류가 있는 채널 상에서의 신뢰적 데이터 전송의 경우이다.

비트 오류는 네트워크의 물리적 구성 요소에서 일반적으로 발생한다.

전송된 모든 패킷이 송신된 순서대로 수신된다고 가정한다.


자동 재전송 요구(Automatic Repeat reQuest, ARQ) 프로토콜을 사용하는데, 이 프로토콜은 제어 메시지를 통해 정확하게 수신되었는지 또는 잘못 수신되어 반복이 필요한지를 수신자가 송신자에게 알려줄 수 있는 재전송을 기반으로 하는 신뢰적인 데이터 전송 프로토콜이다.

비트 오류를 처리하기 위해 ARQ에 3가지 부가 프로토콜 기능이 요구된다.


  • 오류 검출
    • 송신자에게 추가적인 비트를 요구
    • 데이터 패킷의 패킷 체크섬 필드로 확인
  • 수신자 피드백
    • 긍정 응답(ACK)와 부정 응답(NAK) 패킷들을 수신자가 송신자에게 전송
    • 1비트 길이로 0이면 NAK, 1이면 ACK
  • 재전송
    • 수신자에서 오류를 가지고 수신된 패킷은 송신자에 의해서 재전송


rdt 2.0


위에서 설명했듯이 ARQ 프로토콜 기능이 추가되어 송신자는 2개의 FSM을 가지고 있다.

먼저 상위 계층으로부터 데이터를 받는 event가 발생하면, action으로 패킷 체크섬과 함께 전송될 데이터를 포함하는 패킷을 생성 (sndpkt)하고, 그 패킷을 전송한다. udt_send(pkt)

그 다음 피드백을 기다리며 만약 NAK이 전송되면 다시 재전송한다.

ACK가 수신되었다면 액션으로 아무런 행동을 취하지 않고 다시 상위 계층으로부터 데이터를 기다린다.

유의할 점은 ACK, NAK 패킷을 기다리는 동안엔 상위 계층으로부터 데이터를 받을 수 없다는 점이다.

이러한 이유로 rdt 2.0은 전송-후-대기(stop-and-wait) 프로토콜이라고 불린다.


수신 측은 패킷을 받고 손상되었다면 액션으로 NAK 패킷을 만들고 전송한다.

손상되지 않았다면 패킷에서 데이터를 추출하고 데이터를 상위 계층으로 전달한 뒤 ACK 패킷을 만들어 송신자에게 보낸다.


이렇게 보면 정상적이나 치명적인 결함이 있다.

특별히 위에서는 ACK, NAK 패킷이 손상될 가능성을 고려하지 않았다는 점이다.

간단한 해결책은 데이터 패킷에 새로운 필드를 추가하고 이 필드 안에 순서번호(sequence number)를 삽입하는 방식으로 데이터 패킷에 송신자가 번호를 붙이는 것이다.

수신자는 수신된 패킷이 재전송 인지를 결정할 때는 이 순서번호만 확인하면 된다.



rdt 2.1



rdt 2.1


2.0과 다른 점은 순서번호만 추가된 것이다.

따라서 송신자는 똑같이 데이터를 받고 보낸 뒤 피드백을 기다리는데 패킷에 순서번호가 있는 것이다.

수신자는 만약 순서가 바뀐 패킷이 수신되면 이미 전에 수신한 패킷에 대한 ACK 패킷을 전송하고, 손상된 패킷이 수신되면 NAK 패킷을 전송한다.



rdt 2.2



rdt 2.2는 비트 오류를 갖는 채널을 위한 NAK 없는 신뢰적인 데이터 전송 프로토콜이다.

rdt 2.1과 달리 비트 오류 패킷이 발생하면 NAK를 보내는 것이 아닌, 가장 최근에 정확하게 수신된 패킷 번호에 대한 ACK 보낸다.

같은 패킷에 대해 2개의 ACK를 수신한 송신자는 수신자가 두 번 ACK한 패킷의 다음 패킷을 정확하게 수신하지 못했음을 알게 된다.

또한 rdt 2.2에서는 수신자가 반드시 ACK 메시지에 의해서 확인응답하는 패킷의 순서번호를 포함해야 한다는 것이다.

그리고 송신자는 수신된 ACK 메시지에 의해 확인응답된 패킷의 순서번호를 반드시 검사해야만 한다.


rdt 2.2 송신자 FSM

rdt 2.2 sender


rdt 2.2 수신자 FSM

rdt 2.2 receiver



rdt 3.0



rdt 3.0은 비트 오류와 손실 있는 채널 상에서의 신뢰적 데이터 전송의 경우이다.

하위 채널이 패킷을 손실한 경우 1) 어떻게 패킷 손실을 검출할 것인가?2) 패킷 손실이 발생했을 때 어떤 action을 할 것인가?가 다뤄줘야 한다.


우선 첫 번째 문제는 새로운 프로토콜 메커니즘을 추가해야 하는데, 바로 시간이다.

송신자가 데이터 패킷을 전송하고 패킷 또는 수신자의 ACK를 손실했다고 가정했을 때, 송신자에게는 어떠한 응답도 없다.

만약 송신자가 패킷을 잃어버렸다는 것을 확신할 정도로 충분한 시간을 기다릴 수 있다면, 간단하게 재전송될 수 있다.

그러나 얼마나 오래 기다려야 하는지, 너무 오래 기다린다면 오류 복구가 시작될 때 까지 오래 기다려야 한다는 뜻이다.


따라서 패킷 손실이 일어났다는 보장은 없으나, 손실이 일어났을 만한 그런 시간을 현명하게 선택하면 된다.

만일 ACK가 이 시간 안에 수신되지 않는다면 패킷은 재전송된다.

패킷이 손실되지 않더라도 재전송될 수 있는데, 이는 중복 데이터 패킷이 될 가능성이 있으나 rdt 2.2에서는 중복 데이터 패킷에 대한 처리 기능이 있다. (순서번호)


따라서 시간 기반 재전송 메커니즘을 구현하기 위해선 주어진 시간이 경과된 후에 송신자를 중단(인터럽트)할 수 있는 카운트다운 타이머가 필요하다.

그러므로 event 발생 시, 아래와 같이 action 해야 한다.


  1. 매 패킷(첫 번째 또는 재전송 패킷)이 송신된 시간에 타이머를 시작한다.

  2. 타이머 인터럽트에 반응한다. (적당한 행동을 취함)

  3. 타이머를 멈춘다.


아래는 rdt 3.0 송신자 FSM이다.


rdt 3.0


아래는 프로토콜이 패킷 손실 또는 지연 없이 어떻게 동작하는지와 손실된 데이터 패킷을 어떻게 처리하는지를 보여준다.

패킷의 순서 번호가 0과 1이 번갈아 일어나므로, rdt 3.0은 얼터네이팅 비트 프로토콜(alternating-bit protocol)이라고도 부른다.


image


image



파이프라인된 신뢰적 데이터 전송 프로토콜



rdt 3.0은 기능적으로는 정확하나 오늘날의 고속 네트워크에서 보면 성능에 만족할 순 없다.

왜냐하면 rdt 3.0은 전송-후-대기(stop-and-wait) 프로토콜이기 때문이다.


image


stop-and-wait


전송-후-대기 프로토콜은 수신자의 ACK 패킷을 받고 나서야 상위 계층으로부터 데이터 수 있다.

이런 성능 문제를 해결하기 위해 확인응답을 기다리지 않고 여러 패킷을 전송하도록 허용하였다.

이 기술을 파이프라이닝이라고 부른다. 아래는 파이프라이닝이다.


pipelining


파이프라이닝 방식은 신뢰적인 데이터 전송 프로토콜에서 다음과 같은 중요성을 가지고 있다.


  • 순서 번호의 범위가 커져야 한다.
    • 각각의 전송 중인 패킷은 유일한 순서번호를 가져야 하고 거기에 전송 중이고 확인응답이 안 된 여러 패킷이 있을지도 모르기 때문이다.
  • 프로토콜의 송신 측과 수신 측은 한 패킷 이상을 버퍼링해야 한다.
    • 최소한 송신자는 전송되었으나 확인응답 되지 않은 패킷을 버퍼링해야 한다.
  • 필요한 순서번호의 범위와 버퍼링 조건은 데이터 전송 프로토콜이 손실 패킷과 손상 패킷 그리고 상당히 지연된 패킷들에 대해 응답하는 방법에 의존한다.
    • 파이프라인 오류 회복의 두 가지 기본적인 접근 방법으로 N부터 반복 (Go-Back-N,GBN)과 선택적 반복 (Selective Repeat ,SR)이 있다.



N부터 반복(Go-Back-N)



GBN 프로토콜에서 송신자는 확인응답을 기다리지 않고 여러 패킷을 전송할 수 있다.

그러나 파이프라인에서 확인응답이 안 된 패킷의 최대 허용 수 N보다 크지 않아야 한다.

송신자 관점의 순서번호는 아래와 같다.


image


확인 응답이 안된 가장 오래된 패킷의 순서번호를 base로 정의하고, 사용되지 않은 가장 작은 순서번호를 nextseqnum, 전송될 다음 패킷의 순서번호으로 정의한다면, 순서번호의 범위에서 4개의 간격을 식별할 수 있다.


간격 [0,base-1]에서 순서번호는 이미 전송되고 확인응답이 된 패킷에 대응된다.

간격 [base, nextseqnum-1]은 송신은 되었지만 아직 확인응답 되지 않은 패킷에 대응된다.

간격 [nextseqnum,base+N-1]은 상위 계층으로부터 데이터가 도착하면 바로 전송될 수 있는 패킷을 위하여 사용될 수 있다.

간격 base+N 이상의 순서번호는 파이프라인에서 확인응답 안 된 패킷의 확인응답이 도착할 때까지 사용될 수 없다.


위의 사진에서 전송되었으나 아직 확인응답 안 된 패킷을 위해 허용할 수 있는 순서번호의 범위는 순서번호의 범위 상에서 크기가 N인 window로 나타난다.

프로토콜이 동작할 때, 윈도우는 순서번호 공간에서 오른쪽으로 이동되는데 이러한 이유로 N을 윈도우 크기라 부르며, GBN 프로토콜은 슬라이딩 윈도우 프로토콜이라고 부른다.


여기서 왜 확인응답 안 된 패킷의 수를 N값으로 제한해야 하는지에 궁금할 수 있는데, 왜 이 패킷들에게 무한한 번호를 허용하지 않는가?

이 부분은 흐름제어와 혼잡제어 부분에서 설명된다.

실제로 패킷의 순서번호는 패킷 헤더 안의 고정된 길이 필드에 포함되는데, 만약 k가 패킷 순서번호 필드의 비트 수라면, 순서번호의 범위는 [0, 2^k-1]이 된다.


아래는 GBN 송신자와 수신자의 확장된 FSM이다.


GBN sender FSM


GBN 송신자는 3가지 타입의 이벤트에 반응해야 한다.

  • 상위로부터의 호출
    • 호출되면 송신자는 첫째로 윈도우가 가득 찼는지, 즉 N개의 아직 확인응답 되지 않은 패킷이 있는지 확인한다.
    • 만약 윈도우가 가득 차 있지 않다면 패킷이 생성되고 송신되고, 가득 차 있다면 데이터를 상위 계층으로 반환한다.
  • ACK의 수신
    • GBN 프로토콜에서 순서번호 n을 가진 패킷에 대한 확인응답은 누적 확인응답으로 인식된다.
    • 이 누적 확인응답은 수신 측에서 올바르게 수신된 n을 포함하여, n까지의 순서번호를 가진 모든 패킷들에 대한 확인응답이다.
  • 타임아웃 이벤트
    • 타임아웃 발생 시, 송신자는 이전에 송신되었지만 아직 확인응답 되지 않은 모든 패킷을 재전송한다.
    • 즉, base부터 nextseqnum-1까지의 패킷을 전송하고, base 패킷에 대한 타이머를 사용한다.
    • 만일 ACK가 수신되었지만 전송했으나 확인응답 안 된 패킷이 존재한다면 타이머는 다시 시작되고, 없다면 타이머는 멈춘다.


GBN receiver FSM


수신자는 만약 순서번호 n을 가진 패킷이 오류 없이 그리고 순서대로 수신된다면, 수신자는 패킷 n에 대한 ACK를 송신하고 상위 계층에 패킷의 데이터 부분을 전달한다.

그 외의 경우에는 수신자는 그 패킷을 버리고 가장 최근에 제대로 수신된 순서의 패킷에 대한 ACK를 재전송한다.

패킷이 상위 계층에 한 번에 하나씩 전송되므로, 만일 패킷 k가 수신되고 상위 계층에 전달되었다면, 이때는 이미 k보다 낮은 순서번호를 가진 모든 패킷 또한 전달되어 있다는 것을 유념해야 한다.


GBN 프로토콜에서 수신자는 순서번호가 잘못된 패킷을 버리는데 당연한 이유가 있다.

우선, 수신자가 상위 계층에 데이터를 전달해야 한다는 것을 기억해야 한다.


만약 n번째 패킷이 수신되어야 하나, n+1 패킷이 수신되어 이 패킷을 저장하고 n 패킷이 수신된 후 상위 계층에 이 패킷을 전달한다고 하자.

그러나 만약 패킷 n이 손실된다면, GBN 프로토콜에 따라 송신자는 확인응답이 안된 패킷 모두를 재전송할 것이다.

이러한 방식은 수신자 버퍼링이 간단하다는 이점이 있는데 즉, 수신자는 어떤 순서가 잘못된 패킷에 대해 버퍼링을 할 필요가 없다.

수신자가 유지해야 할 것은 단지 다음 순서 패킷의 순서번호이며, 이 값은 expectedseqnum에서 유지된다.


image


위의 사진은 윈도우 크기가 4인 경우에 대한 GBN 프로토콜 동작이다.

윈도우 크기가 4이므로 순서번호 0부터 3까지의 패킷을 송신한다.

그러나 송신을 계속하기 전에 하나 이상의 패킷이 긍정 확인응답되는 것을 기다려야 한다.

수신자의 ACK가 도착했을 때, 윈도우는 오른쪽으로 슬라이드되고 송신자는 하나의 새로운 패킷을 전송한다.

수신 측에서 패킷 2가 손실되었으므로 패킷 3,4,5는 순서가 잘못된 패킷으로 발견되어 제거된다.

패킷 2가 타임아웃되어 확인응답되지 않은 패킷(2,3,4,5) 모두를 재전송한다.


요약하면 GBN은 N만큼 패킷을 연속으로 보낼 수 있고, 문제가 발생하면 그 지점부터 N의 크기만큼 재전송하라는 것이다.

단점은 오류 발생 시 많은 패킷을 재전송해야 한다는 것이다.

자세한 건 아래에서 설명한다.



선택적 반복(Selective Repeat)



GBN 프로토콜은 송신자가 패킷으로 파이프라인을 채우는 것을 가능하게 하여, 전송-후-대기 프로토콜의 채널 이용률 문제를 우회하도록 하고 있으나 GBN 자체에도 성능 문제를 겪는 시나리오가 있다.

특히 윈도우 크기와 대역폭-지연 곱의 결과가 모두 클 때, 많은 패킷들이 파이프라인에 있을 수 있다.

그러나 GBN은 패킷 하나의 오류 때문에 많은 패킷을 재전송하므로, 많은 패킷을 불필요하게 재전송하는 경우가 발생하여, 채널 오류의 확률이 클수록 파이프라인은 불필요한 재전송 패킷으로 채워진다.


SR 프로토콜은 수신자에서 오류가 발생한 패킷을 수신했다고 의심되는 패킷만을 송신자가 다시 전송하므로 불필요한 재전송을 피한다.

필요에 따라 각각의 개별적인 재전송은 수신자가 올바르게 수신된 패킷에 대한 개별적인 확인응답을 요구할 것이다.

윈도우 크기 N은 파이프라인에서 아직 확인응답 안 된 패킷 수를 제한하는데 사용되지만, GBN과는 달리 송신자는 윈도우에서 몇몇 패킷에 대한 ACK를 이미 수신했을 것이다.


image


송신자의 이벤트와 행동은 아래와 같다.

  • 상위 계층으로부터 데이터 수신
    • 상위에서 데이터가 수신될 때, 송신자는 패킷의 다음 순서번호를 검사한다.
    • 순서번호가 송신자 윈도우 내에 있으면, 데이터는 패킷으로 송신되고 그렇지 않으면 GBN처럼 버퍼에 저장되거나 나중에 전송하기 위해 반환한다.
  • 타임아웃
    • 타이머는 손실 패킷을 보호하기 위해 다시 사용된다.
    • 단, 오직 한 패킷만이 타임아웃에 전송되기 때문에, 각 패킷은 자신의 논리 타이머를 가져야 한다.
  • ACK 수신
    • ACK가 수신되었을 때, 송신자는 그 ACK가 윈도우에 있다면 그 패킷을 수신된 것으로 표기한다.
    • 만약 패킷 순서번호가 send_base와 같다면, 윈도우 베이스는 가장 작은 순서번호를 가진 아직 확인응답 되지 않은 패킷으로 옮겨진다. (base+1)
    • 만약 윈도우가 이동하고 윈도우 내의 순서번호를 가진 미전송 패킷이 있다면, 이 패킷들은 전송된다.


수신자는 패킷의 순서와는 무관하게 손상 없이 수신된 패킷에 대한 확인응답을 할 것이다.

순서가 틀린 패킷은 분실된 패킷이 수신될 때까지 버퍼에 저장하고, 손실 패킷이 수신된 시점에서 일련의 패킷을 순서대로 상위 계층에 전달할 수 있다.

수신자의 이벤트와 행동은 아래와 같다.

  • [rcv_base, rcv_base+1] 내의 순서번호를 가진 패킷은 손상 없이 수신된다.
    • 이 경우는 수신된 패킷이 수신자의 윈도우에 속하며, 선택적인 ACK 패킷이 송신자에게 되돌려진다.
    • 만약 이 패킷이 이전에 수신되지 않았던 것이라면, 버퍼에 저장된다.
    • 만약 이 패킷이 rcv_base와 같은 순서번호라면, 이 패킷과 이전에 연속으로 버퍼에 저장된 패킷들은 상위 계층으로 전달된다.
    • 예를 들면, rcv_base=2의 순서번호 패킷이 수신되면, 이 패킷과 3,4,5 패킷이 상위 계층으로 전달된다.
  • [rcv_base-N, rcv_base-1] 내의 순서번호를 가진 패킷이 수신된다.
    • 이 경우에는 이 패킷이 수신자가 이전에 확인응답한 것이라도, ACK가 생성되어야 한다.
  • 이 외의 경우엔 패킷을 무시한다.


image


위의 사진은 손실된 패킷이 나타날 때 까지의 SR의 동직이다.

수신자는 패킷 3,4,5를 버퍼에 저장하고 손실 패킷 2가 재전송되어 수신되었을 때, 2,3,4,5를 상위 계층으로 전달한다.


수신자의 이벤트 중 현재의 윈도우 base보다 아래의 순서번호를 가진 이미 수신된 패킷이 수신되었을 때, 무시하지 않고 재확인하는 것이 중요하다.

이런 재확인이 반드시 필요하다는 것을 알아야하는데 예를 들어, 송신자와 수신자의 순서번호 공간이 주어지면, 수신자가 송신자에게 전파하는 send_base 패킷에 대한 ACK가 없다면, 수신자가 그 패킷을 이미 수신했음이 분명하더라도 결국 송신자는 send_base 패킷을 재전송할 것이다.

또한 송신자의 윈도우는 결코 앞으로 이동하지 않을 것이다.

송신자와 수신자는 올바른 수신과 그렇지 않은 수신에 대해 항상 같은 관점을 갖지는 않을 것이다.

이는 SR 프로토콜에서 송신자와 수신자의 윈도우가 항상 같지는 않다는 의미다.


image


송신자와 수신자 윈도우 사이의 동기화의 부족은 순서번호의 한정된 범위에 직면했을 때 중대한 결과를 가져온다.

예를 들어, 한정된 범위의 네 개의 패킷 순서번호 0,1,2,3과 윈도우 크기 3이 있다.

0부터 2까지의 패킷이 전송되어 수신자에게서 확인이 되었을 때, 송신자의 윈도우와 수신자의 윈도우를 확인해보면 다음과 같다.

송신자는 [0,1,2]이고, 수신자는 순서번호가 [3,0,1]인 4,5,6번쨰 패킷에 있다.


위의 사진에서 두 가지 시나리오를 고려한다.

첫 번째 시나리오에서 처음 3개의 패킷에 대한 ACK가 손실되어 타임아웃 후 송신자는 이 패킷을 재전송한다.

그 다음 수신자는 순서번호가 0(처음 보낸 패킷)인 패킷을 수신한다.


두 번째 시나리오에서, 처음 3개의 패킷에 대한 ACK가 모두 올바르게 전달되었다.

그러면 송신자는 자신의 윈도우를 앞으로 이동시켜 각각의 순서번호가 [3,0,1]인 4,5,6번째 패킷을 보낸다.

순서번호 3을 가진 패킷이 손실되고, 순서번호 0을 가진 패킷(새로운 데이터를 포함한 패킷)은 도착한다.


수신자는 송신자의 action을 볼 수 없으므로, 송신자와 수신자 사이의 커튼이 있다.

수신자의 관점에서 볼 때, 첫 번째 시나리오에서는 과연 순서번호 0 패킷이 재전송된 패킷인가 아니면 새로운 패킷인지 알 수 없는 딜레마에 빠진다.

마찬가지로, 두 번째 시나리오에서도 5번째 패킷(순서번호 0)이 재전송인지 새로운 패킷인지 구분할 수 없다.


물론, 순서번호 공간의 크기보다 1이 작은 윈도우 크기에서는 동작하지 않는다.

그러면 최소한의 윈도우 크기는 얼마인가? 윈도우 크기는 순서번호 공간 크기의 절반보다 작거나 같아야 한다.



패킷 순서 바뀜도 일어나는 채널



이 절에서는 한 가지 가정을 했는데 바로 패킷이 손실될 순 있어도 순서가 바뀌진 않는다는 가정을 하였다.

이는 일반적으로 송신자와 수신자가 단일한 물리적 선으로 연결 되어 있을 때 적합한 가정이다.

그러나 둘을 연결하는 채널이 네트워크일 때, 패킷 순서 바뀜이 일어날 수 있다.


패킷의 순서 바뀜의 현상으로, 송신자와 수신자의 윈도우가 n을 포함하지 않고 있더라도, 순서번호 또는 확인응답번호 n을 가진 오래된 패킷의 복사본들이 생길 수 있다.

순서번호가 재사용될 수 있으므로 그런 중복된 패킷들을 막을 수 있는 조치가 있어야 한다.

실제 방식은 송신자가 순서번호 n을 가진 이전에 송신된 패킷들이 더 이상 네트워크에 없다는 것을 어느 정도 “확신”할 때까지 순서번호가 재사용되지 않음을 확실히 하는 것이다.

이는 패킷이 어느 일정 시간 이상으로 네트워크에서 “존재”할 수 없다는 가정에 의해서 이루어진다.

대략 3분의 최대 패킷 수명 시간이 가정되어 있다.






연결지향형 트랜스포트: TCP



이 절에서는 신뢰적인 데이터 전송을 위해 TCP가 오류 검출, 재전송, 누적 확인응답, 타이머, 순서번호와 확인응답 번호를 위한 헤더필드를 포함한 앞 절에서 논의했던 원칙들을 따르고 있다.



TCP 연결



TCP는 애플리케이션 프로세스가 데이터를 다른 프로세스에게 보내기 전에 핸드셰이킹 과정이 있어서 연결지향형이라고 한다.

즉, 데이터 전송을 보장하는 파라미터들을 각자 설정하기 위한 사전 세그먼트들을 보내야 한다.


TCP 프로토콜은 오직 종단 시스템에서만 동작하고 중간의 네트워크 요소(라우터와 브릿지)에서는 동작하지 않으므로, 중간의 네트워크 요소들은 TCP 연결 상태를 유지하지 않는다.

즉, 중단 라우터들은 TCP 연결을 감지하지 못하고 데이터그램만 본다.


또한, TCP 연결은 전이중(full-deplex) 서비스를 제공한다.

예를 들어, A와 B 프로세서 간 TCP 연결이 있다면, 애플리케이션 계층 데이터는 A에서 B로 흐르는 동시에 B에서 A로 흐를 수 있다.


TCP 연결을 항상 단일 송신자와 단일 수신자 사이의 점대점(point-to-point)이다.

멀티캐스팅은 TCP에서는 불가능하다.


연결이 설정되는 과정은 아래와 같다.

  1. 클라이언트 애플리케이션 프로세스는 서버의 프로세스와 연결을 설정하기를 원한다고 TCP 클라이언트에게 먼저 알린다.
    • clientSocket.connect( (serverName, serverPort) )
  2. 클라이언트가 서버로 TCP 세그먼트를 보내면 서버는 두 번째 특별한 TCP 세그먼트로 응답하고, 마지막으로 클라이언트가 세 번째 특별한 TCP 세그먼트로 다시 응답한다.
    • 처음 2개의 세그먼트에는 애플리케이션 계층 데이터가 없고 3번째 부터 포함 가능하고 두 호스트 간 3개의 세그먼트가 보내지므로 3-way handshake라 한다.
  3. TCP 연결이 설정되었고 두 애플리케이션 프로세스는 서로 데이터를 주고 받는다.


TCP 송신과 수신 버퍼


TCP는 송신 버퍼로 데이터를 보내고 수신 버퍼로 받는다.

TCP는 자신이 편한 대로 세그먼트의 데이터를 전송하며, 언제 버퍼된 데이터를 전송해야 하는지는 정해지지 않았다.


세그먼트의 크기는 최대 세그먼트 크기(maximum segment size, MSS)로 제한된다.

MSS는 헤더를 포함한 TCP 세그먼트의 최대 크기가 아니라, 세그먼트에서의 애플리케이션 계층 데이터에 대한 최대 크기이다.

MSS는 일반적으로 로컬 송신 호스트에 의해 전송될 수 있는 가장 큰 링크 계층 프레임의 길이(최대 전송 단위, maximum transmission unit, MTU)에 의해 일단 결정되고, 그 후 TCP 세그먼트(IP 데이터그램 안에 캡슐화되었을 때)와 TCP/IP 헤더 길이(통산 40바이트)가 단일 링크 계층 프레임에 딱 맞도록 하여 정해진다.


TCP는 TCP 헤더와 클라이언트 데이터를 하나로 만들어 TCP 세그먼트를 형성한다.

세그먼트는 네트워크 계층에 전달되며, 네트워크 계층 IP 데이터그램 안에 각각 캡슐화된다.

TCP가 세그먼트를 수신하면 수신 버퍼에 데이터가 위치하고, 애플리케이션은 수신 버퍼에서 데이터 스트림을 읽는다.



TCP Segment 구조



TCP Segment 구조


TCP segment는 헤더와 데이터 필드로 구성된다.

데이터 필드는 한 줌의 애플리케이션 데이터를 담는다.

MSS는 세그먼트의 데이터 필드의 크기를 제한한다.

TCP가 웹 문서의 이미지와 같은 큰 파일을 전송할 때, 일반적으로 MSS 크기로 파일을 쪼갠다.

그러나 많은 대화식 애플리케이션(텔넷 등)은 MSS보다 작은 데이터 덩어리를 전송한다.


TCP 헤더는 일반적으로 20바이트(UDP 헤더보다 12바이트 크다)이다.

출발지와 목적지 포트번호, 체크섬 필드가 포함되며 아래와 같은 필드가 추가된다.


  • 32비트 순서번호와 확인응답번호

  • 16비트 수신 윈도우
    • 흐름제어에 사용, 수신자가 받아들이려는 바이트의 크기를 나타내는 데 사용된다.
  • 4비트 헤더 길이 필드
    • 32비트 워드 단위로 TCP 헤더의 길이를 나타낸다.
    • 일반적으로 헤더 길이는 20바이트다.
  • 옵션 필드
    • 선택적이고 가변적의 길이를 갖고 송신자와 수신자가 MSS를 협상하거나 고속 네트워크에서 사용하기 위한 윈도우 확장 요소로 이용된다.
  • 6비트 플래그
    • ACK 비트는 이 세그먼트는 성공적으로 수신된 세그먼트에 대한 확인응답
    • CWR, ECE 비트는 명시적 혼합표시에서 사용
    • RST, SYN, FIN 비트는 연결 설정과 해제에 사용
    • PSH 비트는 수신자가 데이터를 상위 계층에 즉시 전댈해야 할 때 사용
    • URG 비트는 이 세그먼트에서 송신 측 상위 계층 개체가 “긴급”으로 표시하는 데이터를 가리킬 때 사용


TCP 세그먼트 구조2



순서번호와 확인응답 번호



TCP 세그먼트 헤더에서 가장 중요한 필드 두 가지는 순서번호 필드와 확인응답 번호 필드이다.

이 필드들은 TCP의 신뢰적인 데이터 전송 서비스의 중대한 부분인데, TCP가 이 필드를 무엇으로 채우는지 먼저 살펴본다.


image


위의 사진은 TCP 세그먼트로 분할되는 파일 데이터이다.

TCP는 데이터를 구조화되어 있지 않고, 단지 순서대로 정렬된 바이트 스트림으로 본다.

TCP의 순서번호 사용은 이러한 관점에서 순서번호는 일련의 세그먼트에 대해서가 아닌, 전송된 바이트 스트림에 대한 것으로, 세그먼트에 대한 순서번호는 세그먼트에 있는 첫 번째 바이트의 바이트 스트림 번호이다.

따라서 위의 사진을 기준으로 하면 MSS가 1000바이트 일 때, 첫 번째 세그먼트는 순서번호 0, 두 번째 세그먼트는 순서번호 1000, 세 번째는 2000이 된다.

즉, 다음 순서번호는 이전 순서번호 + 내가 보낸 바이트 크기이므로 MSS가 1000바이트이므로 0 + 1000 = 1000, 1000+1000=2000가 된다.


확인응답 번호는 순서번호보다 까다롭다.

TCP는 전이중 방식임을 상기하면서 호스트 A, B가 TCP 연결상태(A: 송신자, B: 수신자)이라 가정한다.

호스트 B로부터 도착한 각 세그먼트는 B로부터 A로 들어온 데이터에 대한 순서번호를 갖는다.

호스트 A가 자신의 세그먼트에 삽입하는 확인응답 번호는 호스트 A가 호스트 B로부터 기대하는 다음 바이트의 순서번호이다.


예를 들면, 호스트 A가 B로부터 0에서 535까지 번호가 붙은 모든 바이트를 수신했고 B로 세그먼트를 송신하려 한다고 가정한다.

호스트 A는 호스트 B의 데이터 스트림에서 536번째 바이트와 그 다음에 오는 모든 바이트를 기다리고 있다.

그래서 호스트 A는 세그먼트의 확인응답 번호 필드에 536을 삽입하고 그것을 B에 송신한다.

즉, 1바이트씩 보냈기 때문에 호스트 A는 호스트 B의 다음 순서번호인 535+1=536을 ACK 값으로 보낸 것이다.


다른 예로, 호스트 A는 B로부터 0~535, 900~1000의 바이트를 포함한 세그먼트를 수신했다고 가정한다.

어떤 이유에서 536~899의 바이트를 포함한 세그먼트는 아직 수신하지 않았으므로 호스트 A는 B의 데이터 스트림을 재생성하기 위해서 536번째 바이트를 아직 기다리고 있다.

그러므로 B에 대한 A의 다음 세그먼트는 확인응답 번호 필드에 536을 가질 것이다.

TCP는 스트림에서 첫 번째 잃어버린 바이트까지의 바이트들까지만 확인응답하기 때문에, TCP는 누적 확인응답을 제공한다고 한다.


마지막 예는 중요하면서 민감한 문제로, 호스트 A는 세 번째 세그먼트를 두 번째 세그먼트가 수신되기 전에 수신하였다.

그러므로 세 번째 세그먼트는 순서가 틀리게 도착하였다.

민감한 문제는 TCP 연결에서 순서가 틀린 세그먼트를 수신할 때, 호스트는 어떤 행동을 하는가에 대한 것이다.

RFC에는 여기에 어떤 규칙도 부여하지 않았고, TCP 구현 개발자에게 맡기고 있다.

기본적으로 두 가지 선택이 있다.

  • 수신자가 순서를 틀린 세그먼트를 즉시 버린다.
    • 수신자 설계를 단순화할 수 있다.
  • 수신자는 순서가 틀린 데이터를 보유하고, 빈 공간에 잃어버린 데이터를 채우기 위해서 기다린다.
    • 네트워크 밴드폭 관점에서는 효율적이며, 실제에서도 취하는 방법이다.


시작 순서번호는 임의로 선택할 수 있으며 이것은 두 호스트 사이에 이미 종료된 연결로부터 아직 네트워크에 남아 있던 세그먼트가 같은 두 호스트 간의 나중 연결에서 유효한 세그먼트로 오인될 확률을 최소화한다.



텔넷으로 본 순서번호와 확인번호



텔넷은 TCP 상에서 동작하며, 한 쌍의 호스트들 사이에서 동작하도록 설계되었다.


image


초기 순서번호가 클라이언트와 서버 사이에서 각각 42와 79라고 가정한다.

세그먼트의 순서번호는 데이터 필드 안에 있는 첫 번째 바이트의 순서번호이므로 클라이언트는 순서번호 42, 서버는 순서번호 79를 가질 것이다.

확인응답 번호는 호스트가 기다리는 다음 바이트의 순서번호이므로 서버는 ACk 43을 가질 것이다.



왕복시간(RTT) 예측과 타임아웃



TCP는 rdt 프로토콜처럼 손실 세그먼트를 발견하기 위해 타임아웃/재전송 메커니즘을 사용한다.

개념은 간단하나, TCP 같은 실직적인 프로토콜에서의 구현은 미묘한 사항이 많은데, 타임아웃이 복잡하다.


타임아웃은 연결의 RTT보다 좀 커야 한다. 즉, 세그먼트가 전송된 시간부터 긍정 확인응답 될 때까지의 시간이다.

만약 그렇지 않으면, 불필요한 재전송이 발생할 것이다.



RTT 예측



SampleRTT라고 표시되는 세그먼트에 대한 RTT 샘플은 세그먼트가 송신된 시작(즉, IP에게 넘겨진 시간)으로부터 그 세그먼트에 대한 긍정응답이 도착한 시간까지의 시간 길이이다.

모든 전송된 세그먼트에 대해서 SampleRTT를 측정하는 대신, 대부분의 TCP는 한 번에 하나의 SampleRTT 측정만을 시행한다.

즉, SampleRTT는 전송되었지만 현재까지 확인응답이 없는 세그먼트 중 하나에 대해서만 측정되고 재전송한 세그먼트에 대해서는 계산하지 않으며 한 번 전송된 세그먼트에 대해서만 측정한다.


SampleRTT 값은 라우터에서의 혼잡과 종단 시스템에서의 부하 변화 때문에 세그먼트마다 달라 값이 불규칙적이다.

따라서 RTT를 추정하기 위해 평균치를 이용, EstimatedRTT를 이용하고, TCP는 SampleRTT의 평균을 유지한다.

ACK를 수신하고 새로운 SampleRTT를 흭득하자마자 TCP는 평균값을 갱신한다.
EstiamtedRTT = (1-a) * EstimatedRTT + a * SampleRTT
권장되는 a의 값은 0.125이다.


image


RTT 예측 외에도 RTT 변화율을 측정하는 것도 매우 중요하다.

RTT 변화율은 DevRTT라 하고, 이 값은 SampleRTT가 EstimatedRTT로부터 얼마나 많이 벗어나는지에 대한 예측으로 정의한다.
DevRTT = (1-b) * DevRTT + b * | SampleRTT - EstimatedRTT |
b의 권장값은 0.25이다.
SampleRTT 값이 어떤 변화도 없다면 DevRTT는 작게 되고, 아니라면 DevRTT는 클 것이다.



재전송 타임아웃 주기의 설정 및 관리



TCP 타임아웃 주기에는 어떤 값이 사용되어야 하는가?

주기는 EstimatedRTT보다 크거나 같아야 한다. 그렇지 않다면 불필요한 재전송이 보내질 것이다.

그러나 타임아웃 주기는 EstimatedRTT보다는 너무 크면 안된다.

너무 크면 세그먼트를 잃어버렸을 때, TCP는 세그먼트의 즉각적인 재전송을 하지 않게 된다.


타임아웃 값은 EstimatedRTT에 약간의 여유 값을 더한 값으로 설정하는 것이 바람직하다.

SampleRTT 값에 많은 변동이 있을 땐 여유 값이 커야하며, 변동이 작을 땐 작아야 한다.

따라서 DevRTT의 값이 역할을 하게 된다.


따라서 타임아웃 값은 TimeoutInterval = EstimatedRTT + 4 * DevRTT



신뢰적인 데이터 전달



TCP는 인터넷의 네트워크 계층 프로토콜 IP의 비신뢰적인 최선형 서비스에서 신뢰적인 데이터 전달 서비스를 제공한다.

TCP의 신뢰적인 데이터 전달 서비스는 프로세스가 자신의 수신 버퍼로부터 읽은 데이터 스트림이 손상되지 않았으며 손실이나 중복이 없다는 것과 순서가 유지된다는 것을 보장한다.


신뢰적인 데이터 전송 과정에서 개별적인 타이머가 “전송되었지만 아직 확인응답을 받지 못한 각각의 세그먼트”와 한 쌍이 되어 동작한다고 가정하였다.

이론상 훌륭하지만, 타이머 관리는 상당한 오버헤드를 요구할 수 있으므로 “전송되었지만 확인응답이 안 된 다수의 세그먼트”들이 있다 하더라도, 권장되는 TCP 타이머 관리 절차에서는 오직 단일 재전송 타이머를 사용한다.


TCP가 어떻게 신뢰적인 데이터 전송을 제공하는지 2개의 점진적인 단계가 있다.

  1. 손실 세그먼트를 복구하기 위해 타임아웃만을 사용하는 간소화된 TCP 송신자

  2. 타임아웃에 추가하여 중복 확인응답을 이용


TCP 송신자의 데이터 전송/재전송에 관련된 세 가지 주요 이벤트가 있는데 바로 상위 애플리케이션으로부터 수신된 데이터, 타이머 타임아웃 그리고 ACK 수신이다.

아래는 그에 대한 액션이다.

  • 상위 애플리케이션으로부터 수신된 데이터
    • 데이터를 받고, 세그먼트로 이 데이터를 캡슐화하고, IP에게 넘긴다.
    • 타이머는 이 세그먼트를 IP로 넘길 때 시작, 타임아웃 주기는 TimeoutInterval 값
  • 타임아웃
    • 타임아웃을 일으킨 세그먼트를 재전송하여 응답하고, 타이머를 다시 시작한다.
  • ACK 수신
    • TCP는 변수 sendBase와 ACK값을 비교한다. sendBase는 “수신 확인응답이 확인되지 않은 가장 오래된 바이트의 순서번호”이다.
      • sendbase-1은 수신자에게 정확하고 차례대로 수신되었음을 알리는 마지막 바이트의 순서번호
    • TCP는 누적 확인응답을 사용하므로 ACK값 y는 y바이트 이전의 모든 바이트들의 수신을 확인한다.
      • 만일 y > sendBase이면, ACK는 이전에 확인응답 안 된 하나 이상의 세그먼트들을 확인해준다.
      • 따라서 송신자는 자신의 sendBase 변수를 갱신하고, 아직 확인응답 안된 세그먼트들이 존재하면 타이머를 다시 시작한다.



TCP 재전송 시나리오



이 프로토콜이 어떻게 작동하는지 몇 가지 간단한 시나리오를 통해 알아본다.


image


첫 번쨰 시나리오는 ACK가 유실된 경우이다.

A로부터의 세그먼트가 B 측에서 수신되었음에도 불구하고 B로부터 A로의 긍정 확인응답이 손실된다면, 이런 경우에 타임아웃이 일어나고, 호스트 A는 동일한 세그먼트를 B에게 재전송한다.

물론, B는 재전송 세그먼트를 수신하면 세그먼트를 버린다.


image


두 번째 시나리오는 ACK가 전송되는 도중 타임아웃이 발생한 경우이다.

호스트 A가 seq=92, 100을 보냈고 호스트 B는 ACK로 92+8바이트=100, 100+20바이트=120을 보낸다.

여기서 seq=92의 세그먼트의 ACK가 오지 않아 타임아웃 되어서 재전송한다.

타임아웃 이벤트가 발생할 때, 타임아웃을 일으킨 세그먼트를 재전송하고 단일 타이머가 재시작된다.

새로운 타임아웃 이전에 두 번째 세그먼트의 ACK가 도착하면 두 번째 세그먼트는 재전송을 하지 않을 것이다.


image


세 번째 시나리오는 ACK가 유실되었지만 그 다음 ACK가 정상적으로 도착한 경우이다.

첫 번째 세그먼트의 ACK가 분실되었지만, 그 다음 세그먼트의 ACK가 도착하면, 송신자는 수신자가 모든 데이터를 정상적으로 수신했다는 것을 알게 되므로 재전송 하지 않는다.



타임아웃 주기의 두 배로 설정



타임아웃이 발생할 때마다 TCP는 “아직 확인응답이 안된 가장 작은 순서번호를 가진” 세그먼트를 재전송한다.

그러나 TCP는 재전송 때 마다 마지막 EstimatedRTTDevRTT로부터 타임아웃 값을 가져오는 것이 아니라, 타임아웃 주기를 이전 값의 두 배로 설정한다.


예를 들면, 타이머가 만료되었을 때 가장 이전의 확인응답이 안 된 세그먼트의 TimeoutInterval이 0.75라고 가정한다.

TCP는 이 세그먼트를 재전송하고, 타임아웃 주기를 0.75의 2배인 1.5초로 설정한다.

만약 타이머가 다시 1.5초가 경과한 후에 만료되면, TCP는 다시 그 세그먼트를 재전송하고 타임아웃 주기를 3초로 설정한다.


따라서 이 주기는 각 재전송 후에 지수적으로 증가한다.

단, 상위 계층으로부터의 데이터 수신이나 ACK를 수신하는 이벤트가 발생 시, 이후 타이머가 시작될 때 타임아웃 주기는 EstimatedRTTDevRTT의 가장 최근 값에서 가져온다.


이것은 제한된 형태의 혼잡제어를 제공한다.

타이머 만료는 주로 네트워크에서의 혼잡에 의해 발생한다.

즉, 출발지와 목적지 사이의 경로에서 하나 이상의 라우터 큐에 도착한 많은 패킷은 패킷의 손실이나 오랜 큐 대기의 원인이 된다.

혼잡할 때 출발지에서 지속적으로 패킷의 재전송을 고집하면 그 혼잡은 더욱 악화될 것이다.

대신에 TCP는 송신자가 더 긴 간격으로 재전송하도록 한다.



빠른 재전송



타임아웃이 유발하는 재전송의 한 가지 문제는 타임아웃의 주기가 때때로 비교적 길다는 점이다.

긴 타임아웃 주기는 패킷을 재전송하기 전 까지 송신자를 오랫동안 기다리게 해서 종단간 지연을 증가시킨다.


송신자는 중복 ACK를 통해 패킷이 손실됬음을 알 수 있다.

수신자가 기다리는 순서번호보다 더 큰 순서번호의 세그먼트를 수신받는다면, 마지막으로 수신된 순서적인 바이트를 갖는 데이터를 다시 수신 확인응답(즉, 중복 ACK를 생성)를 보낸다.

송신자는 만약 3개의 중복 ACK를 수신한다면, ACK된 세그먼트의 다음 3개의 세그먼트들이 분실됬음을 의미한다는 걸 알 수 있다.

3개의 중복 ACK를 수신하는 경우에는 TCP는 세그먼트의 타이머가 만료되기 전에 손실 세그먼트를 재전송하는 빠른 재전송을 한다.


fast retransmission


위의 사진으로 보면, 두 번째 세그먼트를 잃어버린 경우, 타이머가 만료되기 전에 재전송되었다.



GBN? Or SR?



TCP가 GBN 프로토콜인가 SR 프로토콜인가? 결론부터 말하면 둘의 혼합으로 보면 된다.


TCP 송신자는 송신되고 확인응답 안 된 바이트의 가장 작은 순서번호(sendBase)와 전송될 다음 바이트의 순서번호(NextSeqnum)를 유지해야 한다.

이 부분은 GBN과 많이 비슷해보인다.

그러나 몇 가지 차이점이 있는데, 많은 TCP 구현은 올바르게 수신되었지만 순서가 바뀐 세그먼트들을 버퍼링한다.
GBN는 수신자가 순서가 잘못된 패킷을 수신하면 그 패킷을 버리고 최근 ACK를 송신한다.


예를 들면, 세그먼트의 순서번호가 1 ~ N인 세그먼트를 전송하고 수신 측에 오류 없이 순서대로 도달한다고 가정한다.

여기서 순서 번호 n < N인 패킷에 대한 ACK가 손실되었지만, 나머지의 ACK는 송신 측에 도달했다고 가정한다.

이 예에서, GBN은 패킷 n뿐만 아니라 n, n+1, n+2, ..., N 모두를 재전송하지만, TCP는 n 하나만 재전송하면 된다.

또한, TCP는 세그먼트 n에 대한 타임아웃 전에 세그먼트 n+1에 대한 ACK를 받으면 n 패킷을 재전송하지 않는다.


TCP는 원래의 SR과 유사하다.



흐름제어



TCP는 데이터를 수신하면 수신 버퍼에 저장하고 해당 애플리케이션 프로세스는 버퍼에서 데이터를 읽지만, 데이터가 도달한 시점에서 읽어야 할 필요는 없다.

애플리케이션이 다른 작업으로 바뻐서 오랜 시간 데이터를 읽지 않는 등 애플리케이션이 데이터를 읽는 속도가 비교적 느리다면, 송신자는 점점 더 많은 데이터를 빠르게 전송함으로써 연결의 수신 버퍼에 아주 쉽게 오버플로우를 발생시킨다.


TCP는 송신자가 수신자의 버퍼를 오버플로 시키는 것을 방지하기 위해서 애플리케이션에게 흐름제어 서비스(flow-control service)를 제공한다.

흐름제어는 속도를 일치시키는 서비스로, 수신하는 애플리케이션이 읽는 속도와 송신자가 전송하는 속도를 같게 한다.

흐름제어와 혼잡제어는 비교적 하는 일이 비슷하나(송신자 억제) 명백히 서로 다른 목적을 위해 수행된다.


전체 내용을 살펴보기 위해 이번엔 TCP 수신자가 순서가 틀린 세그먼트를 버린다고 가정한다.

TCP는 송신자가 수신 윈도우(receive window, rwnd)라는 변수를 유지하여 흐름제어를 제공한다.

수신 윈도우는 수신 측에서 가용한 버퍼 공간이 얼마나 되는지를 송신자에게 알려 주는데 사용된다.

TCP는 전이중이므로 각 측의 송신자는 별개의 수신 윈도우를 유지한다.


수신 윈도우와 수신 버퍼


TCP 연결 상에서 호스트 A가 호스트 B에게 큰 파일을 전송한다고 가정할 때, 호스트 B는 이 연결에 수신 버퍼를 할당한다.

이때 할당된 수신 버퍼의 크기를 RcvBuffer라고 하고, 시간 나는 대로 호스트 B의 애플리케이션 프로세스는 버퍼로부터 데이터를 읽으며 다음과 같은 변수를 정의한다.


  • LastByteRead
    • 호스트 B의 애플리케이션 프로세스에 의해서 버퍼로부터 읽힌 데이터 스트림의 마지막 바이트 수
  • LastByteRcvd
    • 호스트 B에서 네트워크로부터 도착하여 수신 버퍼에 저장된 데이터 스트림의 마지막 바이트 수


TCP는 할당된 버퍼의 오버플로를 허용하지 않으므로 LastByteRcvd - LastByteRead <= RcvBuffer라는 수식이 가능하며, 수신 윈도우는 버퍼의 여유 공간으로 설정된다.

따라서 rwnd = RcvBuffer - [LastByteRcvd - LastByteRead]이고, 시간에 따라 여유 공간은 변하므로 rwnd는 동적이다.


호스트 B는 호스트 B가 호스트 A에게 전송하는 모든 세그먼트의 윈도우 필드(receive window 필드)에 현재의 rwnd 값을 설정함으로써 연결 버퍼에 얼마만큼의 여유 공간이 있는지를 호스트 A에게 알려 준다.

초기에는 호스트 B가 rwnd=RcvBuffer로 설정하고 이를 성사시키기 위해선 위에서 사용한 변수들을 유지해야 한다.


호스트 A는 두 변수 LastByteSentLastByteAcked를 유지한다.

LastByteSent - LastByteAcked는 호스트 A가 이 연결에 전송 확인응답이 안 된 데이터의 양이다.

rwnd의 값보다 작은 확인응답 안 된 데이터의 양을 유지함으로써 호스트 A는 호스트 B의 수신 버퍼에 오버플로가 발생하지 않는다는 것을 확신한다.

호스트 A는 연결되어 있는 동안 아래의 식을 보장한다.
LastByteSent - LastByteAcked <= rwnd


단, 이 방법에는 사소한 기술적 문제가 있다. 호스트 B의 수신 버퍼가 가득 찼다고 가정한다.

호스트 A에게 rwnd=0이라 알린 후에 호스트 B는 호스트 A에게 전송할 게 없다고 가정한다.

호스트 B의 애플리케이션 프로세스가 버퍼를 비우더라도 호스트 B는 호스트 A에게 새로운 rwnd로 새로운 세그먼트를 전송하지 않는다.

즉, 호스트 A는 호스트 B의 수신 버퍼에 약간의 공간이 있음을 알지 못하며, 호스트 A는 차단되고 더 이상 데이터를 전송할 수 없다.


이 문제를 해결하기 위해 TCP 명세서는 호스트 A가 호스트 B의 수신 윈도우가 0일 때, 1바이트 데이터로 세그먼트를 계속해서 전송하도록 요구한다.

이 세그먼트들은 수신자에 의해 ACK를 보낼 것이고, 결과적으로 버퍼는 지워지고 ACK는 rwnd가 0이 아니라고 알릴 것이다.



TCP 연결 관리



TCP 연결이 어떻게 설정되고 해제되는지를 알아본다.


TCP 3-way handshake


  • 1단계
    • 먼저 클라이언트 측 TCP는 서버 TCP에게 특별한 TCP 세그먼트를 송신한다.
      • 이 특별한 세그먼트는 애플리케이션 계층 데이터를 포함하지 않고, SYN 플래그 비트를 설정한다.
    • 이 특별한 세그먼트를 SYN 세그먼트라 부르고, 최초의 순서번호를 설정하여 순서번호 필드에 이 번호를 넣는다.
    • 이 세그먼트는 IP 데이터그램 안에서 캡슐화되고 서버로 송신된다.


  • 2단계
    • 서버는 데이터그램에서 TCP SYN 세그먼트를 추출하고 연결에 TCP 수신 버퍼와 변수들을 할당한다.
    • 클라이언트 TCP로 ACK를 송신하며, 이 연결 승인 세그먼트 또한 애플리케이션 계층 데이터를 포함하지 않는다.
      • 단, 3가지 중요한 정보를 포함하는데, SYN 비트는 1로 설정하고 확인응답 필드 값은 client_isn+1로 설정되며 마지막으로 서버는 자신의 최초 순서번호(server_isn)을 순서번호 필드에 넣는다.
    • 이 연결 승인 세그먼트를 SYNACK 세그먼트로 불린다.


  • 3단계
    • SYNACK 세그먼트를 수신하면, 클라이언트는 연결에 버퍼와 변수들을 할당하고 서버로 또 다른 세그먼트를 송신한다.
    • 이 마지막 세그먼트가 서버의 연결 승인 세그먼트를 수신했음을 알리는 세그먼트이고, 연결이 설정되었음으로 SYN 비트는 0으로 설정된다.


위의 3-way handshake 과정이 끝나면, 클라이언트와 서버 호스트들은 각각 서로에게 데이터를 포함하는 세그먼트를 보낼 수 있다.

TCP 연결에 참여하는 2개의 프로세스 중 하나는 연결을 끝낼 수 있으며, 연결이 끝날 때 호스트의 자원(버퍼와 변수들)은 회수된다.


TCP 연결 해제


클라이언트가 연결을 종료한다고 할 때, 클라이언트 프로세스는 종료 명령을 내리는데 클라이언트 TCP가 서버 TCP로 특별한 세그먼트(FIN비트 1로 설정)를 보낸다.

서버가 이 세그먼트를 수신하면, 서버는 클라이언트에게 ACK를 보내고, 그 다음 다시 FIN비트를 설정한 세그먼트를 클라이언트 TCP에게 보낸다.

마지막으로 클라이언트는 서버의 종료 세그먼트에 확인 응답을 한다.

이 시점에서 두 호스트의 모든 자원들은 할당이 해제된다.


아래는 클라이언트와 서버의 TCP에서 TCP 상태 변이의 순서를 나타낸 것이다.


TCP Client


TIME WAIT 상태는 TCP 클라이언트가 ACK가 손실된 경우에 마지막 확인응답을 재송신하도록 한다.

대체로 30초에서 1분 또는 2분이다.


TCP Server


위의 경우는 클라이언트와 서버 모두 통신할 준비가 되어 있다고 가정했다.

만약 그렇지 않은 경우에는 어떤 일이 발생하는가 ?


예를 들면, 목적지 포트 80을 포함하는 TCP SYN 패킷을 수신하지만, 호스트는 80포트에서의 연결을 수락하지 않고 있다고 가정한다.

그러면 호스트는 출발지로 특별한 리셋 세그먼트(RST 비트 1로 설정)를 보낼 것이다.
즉, 출발지에게 “그 세그먼트에 대한 소켓을 가지고 있지 않으니 세그먼트를 재전송 하지 말라”라고 말하는 것이다.


nmap을 이용해 목표 호스트 TCP 포트 6789를 살펴보기 위해 SYN 세그먼트를 보냈다고 가정한다.

그럼 아래와 같은 3가지 가능한 결과가 있다.

  • 목표 호스트로부터 TCP SYNACK 세그먼트 수신
    • 이것은 애플리케이션이 목표 호스트상에서 TCP 포트 6789를 가지고 실행되는 것을 의미. nmap은 open을 반환
  • 목표 호스트로부터 TCP RST 세그먼트 수신
    • 이것은 SYN 세그먼트가 목표 호스트에 도달했으나 6789 포트를 가진 애플리케이션을 목표 호스트가 실행하지 않는 것을 의미
    • 하지만 공격자는 최소한 포트 6789로 호스트를 목적지로 하는 세그먼트가 출발지와 목표 호스트 간의 경로상에 어떠한 방화벽에도 차단되지 않음을 알게 된다.
  • 출발지가 아무것도 수신받지 못함
    • 이것은 SYN 세그먼트가 중간에 있는 방화벽에 의해 차단되어 목표 호스트에 전혀 도달하지 않는다는 것을 의미하기 쉽다.


SYN Flooding Attack
ind2x.github.io/posts/Dos_Attack/#syn-flooding






Transport Layer 2



Link
ind2x.github.io/posts/Transport_Layer_2/






참고



Link
justlog.tistory.com/m/8 - RDT Protocol
justlog.tistory.com/m/11 - GBN & Selective repeat
justlog.tistory.com/m/15 - TCP
velog.io/@tonyhan18/series/21-기초컴퓨터네트워크
cnsr.dev/index_files/Classes/Networking/Content/03-Transport.html






This post is licensed under CC BY 4.0 by the author.