Transmission Control Protocol
TCP 프로토콜
- L4에서 신뢰성 서비스를 제공해주는 프로토콜이다.
TCP Services (TCP 주요기능)
- TCP에서 제공하는 네트워크 서비스들은 아래와 같다:
- Process to Process Communication (TCP/UDP 공통)
- 포트번호를 통한 프로세스 간 통신 기능 - Stream Delivery Service
- 데이터를 바이트 단위의 스트림의 형태로 송수신하는 기능
(IP, UDP는 비트 단위로 송수신한다.) - Full-Duplex Communication
- 동시 송수신 기능 - Multiplexing and Demultiplexing (TCP/UDP 공통 제공)
- 송수신자 각자가 개별적으로 포트번호를 통한 Muxing/DeMuxing을 통해 논리적으로 연결하는 기능 - Encapsulation and Decapsulation (TCP/UDP 공통 제공)
- TCP 5-Layer에 의거한 패킷 캡슐화/디캡슐화 - Connection-Oriented Service
- 3 Phase를 거치며 안전히 Connection을 생성·유지·종료하는 기능 - Reliable Service
- 패킷이 손실없이 온전하게 송수신되게 하는 기능
1. Process to Process Communication (TCP/UDP 공통 제공)
- TCP는 포트 번호를 이용하여 Machine 내부의 프로세스 간 통신을 지원한다.
- 13번 포트번호를 가진 Daytime 프로토콜은 TCP와 UDP에 공통적으로 쓰인다.
- 가장 많이 쓰이는 20, 21번의 FTP 프로토콜은 파일 전송 기능을 담당한다.
- 53번 포트번호를 가진 DNS는 기본적으로 UDP를 사용하지만,
DNS에서 TCP 서비스가 필요한 상황에서는 TCP의 프로토콜처럼 사용된다.
(보통 서버와 서버 사이에서 TCP 서비스를 요구한다.)
- 이외에 23번 TELNET, 25번 SMTP, 80번 HTTP가 많이 사용되는 프로토콜에 속한다.
2. Stream Delivery Service
- TCP에서 패킷은 Stream Delivery Service를 통해 송신된다.
- 즉, 패킷을 구성하는 모든 Byte들이 순서에 맞춰서 Sending Process에서 Receiving Process에게 전달된다.
- TCP에는 Incoming Buffer, Outgoing Buffer가 모두 존재한다.
(UDP에는 Incoming Buffer만 존재한다.)
- Buffer에 일정량 이상의 패킷이 쌓이면(Pulling Service) Receiving Process로 전달되는 구조이다.
- 단, 패킷 송신시 패킷이 누락될 것을 대비하여, 패킷을 복사하여 전송하는 방식이며,
송신된 패킷에 대한 ACK 신호가 수신되면 이에 해당되는 패킷을 삭제한다.
- Receiving Process의 Buffer에는 순서대로 도착한 패킷을 순서대로 쌓아(Pushing Service)
이전에 도착한 패킷들의 맨 뒤에 위치하게 된다.
- Receiving Process의 Buffer에서 Pulling Service를 통해 Receiving Process에 패킷이 전달된다.
3. Full-Duplex Communication
- TCP에서는 데이터의 동시 송수신이 가능하다. (전이중 연결 방식이다.)
4. Multiplexing and Demultiplexing (TCP/UDP 공통 제공)
- Sender는 패킷을 보내는 프로세스의 포트 번호를 이용하여 패킷을 Multiplexing한다.
- Receiver는 패킷을 수신하는 프로세스의 포트 번호를 이용하여 패킷을 Demultiplexing한다.
5. Encapsulation and Decapsulation (TCP/UDP 공통 제공)
- Sender는 패킷을 Encapsulation하며, Receiver는 패킷을 점검한 후, Decapsulation한다.
- 그림과 달리, 대부분의 Frame 후미에는 Frame Trailer가 붙어있다.
- Frame Trailer에는 일반적으로 EDC가 저장된다.
- Payload는 Data를 의미한다.
6. Connection-Oriented Service
- TCP에는 Incoming Buffer와 더불어, Outgoing Buffer도 사용함으로써, 패킷을 순서대로 전송한다.
- TCP와 UDP에는 공통적으로 Incoming Buffer를 보유하고 있는데, 이 Incoming Buffer의 구성에 차이가 있다.
TCP Incoming Buffer | UDP Incoming Buffer |
- TCP에서는 Connection 당 하나의 Buffer가 할당된다. - 각각의 Client마다 Connection을 개별적으로 구성하며, 각 Connection마다 하나의 Queue를 배정한다. - 각각의 송신자가 보내는 패킷들이 섞이지 않는다. |
- UDP에서는 Port 당 하나의 Buffer가 할당된다. - 포트에 하나의 Queue가 배정되므로, 여러 Client로 부터 도착된 패킷들이 섞일 수 있다. - UDP에서는 순서, 송신자를 구분할 필요가 없다. |
7. Reliable Service
* TCP Reliable Services (TCP 신뢰성 서비스) (URL)
- UDP와 달리, TCP에서는 신뢰성 서비스들을 제공한다.
- 신뢰성 서비스는 아래와 같이 구성된다:
- Error Control
- Flow Control
- Congestion Control
(Flow Control, Congestion Control은 Window 개념에 기반을 두고 있다.)
- 신뢰성 서비스를 이루는 메커니즘은 아래와 같다:
- EDC(Error Detection Code)
- ACK, Time-Out
- 재전송
- Sequence Number
- Window
TCP Segments (TCP 패킷)
- TCP Segment는 Header(20~60 Byte)와 Data로 구성된다.
- 헤더 중 20 Byte는 표준헤더이며, 나머지는 Option 헤더이다.
Source Port Address & Destination Port Address (16 bits, 16 bits)
- UDP와 공통적으로, Source와 Destination의 포트 번호가 저장된다.
Sequence Number (32 bits)
- 첫 번째 Byte Number가 저장된다.
Acknowledgment number (32 bits)
- ACK Control Field값이 1인 경우, Acknowledgment number에 ACK 값이 저장된다.
- ACK 값 또한 Byte Number이다.
HLEN (4 bits)
- 옵션 헤더가 존재하므로, 데이터와 구분짓기 위해 Header Length 값이 필요하다.
- IP에서와 마찬가지로, 4Byte 단위로 저장된다.
(즉, HLEN = 9이면, 전체 헤더의 길이는 36 Byte이다. 또한, 옵션 헤더의 길이는 16 Byte임을 추론할 수 있다.)
Reserved (6 bits)
- 추후 사용을 위해 예약해놓은 bit 필드이다.
Control Flags (1 bit each)
Window Size (16 bits)
- 오류/흐름/혼잡 제어 (신뢰성 서비스) 제공시에 사용되는 필드이다.
Checksum (16 bits)
- TCP 헤더에는 UDP와 마찬가지로, IP Pseudo Header가 붙게 된다.
- Pseudo Header의 8-bit protocol 필드에는 TCP임을 의미하는 값이 저장된다.
- Pseudo Header의 16-bit TCP total length 필드에는 패킷 길이가 저장된다.
(UDP와 달리, TCP 헤더에는 TCP Total Length 필드가 존재하지 않아 패킷 길이를 직접 계산하여 저장해야 한다.)
- Checksum 필드에는 16 bits 씩 분할한 후, 더한 값들을 저장한다. 따라서, 옵션 헤더가 16 bits 단위가 아닌 경우, Padding을 삽입해야 한다.
※ UDP와 달리, TCP에서 Checksum 필드는 Mandatory(의무사항)이다. 즉 필수적으로 값이 저장되어야 한다.
Urgent Pointer (16 bits)
- URG Control 신호가 1일 경우, Urgent Pointer는 Urgent Data의 끝부분을 지목한다.
1) URG (Urgent Pointer is Valid)
- URG가 1이면, 해당 패킷의 데이터 부분에 Urgent Data*가 위치하고 있음을 의미한다.
- 헤더에 포함된 Urgent Pointerr는 Urgent Data의 끝 부분을 포인팅하고 있어 Urgent Data의 크기와 나머지 일반 Data가 시작되는 지점을 알 수 있다.
- URG가 감지되면, Urgent Data는 Incoming Buffer를 거치기 않고 바로 프로세스에 전달된다. (Out-of-Band 전송)
- Urgent Data 뒤에 남은 일반 Data는 정상적으로 Incoming Buffer에 삽입된다. (In-Band 전송)
- 즉, 일반 데이터는 In-Band 전송, Urgent 데이터는 Out-of-Band 전송된다.
* Urgent Data
- 네트워크 프로그램에서 CTRL+C(Interrupt)와 같이 프로세스에 바로 전달되어야 하는 신호(데이터)를 의미한다.
ex) 만약 Urgent Data로써, Interrupt를 수신하면 Incoming Buffer에 있는 데이터를 모두 삭제하고 프로세스를 종료한다.
2) ACK (Acknowledgment is valid)
- ACK가 1인 것은 Acknowledgment Number 필드에 저장된 값이 유의미한 것을 의미한다.
- 또한, ACK 신호가 가고 있음을 의미한다.
3) PSH (Request for Push)
- User가 Control할 수 없는 신호이다. (논외로 간주)
4) RST (Reset the Connection)
- TCP에서 어떠한 오류로 인해, Connection Teardown 하기 위한 신호이다.
5) SYN (Synchronize Sequence Numbers)
- TCP에서 Data를 주고 받기 이전에 Connection Establishment 를 위한 신호이다.
6) FIN (Terminate the Connection)
- TCP에서 아무런 오류 없이 Data를 주고 받은 이후에 정상적으로 Connection Teardown 하기 위한 신호이다.
- Sending Buffer에서는 한 Byte씩 전송하는 것이 아닌, 충분한 크기의 Byte를 하나의 Segment로 구성하여 전송한다.
TCP Numbering System
- TCP에서는 패킷마다 Seq #(Sequence Number)를 부여하는 Numbering System이 존재한다.
- TCP에서 Seq #과 ACK Number는 Byte Number이며, Packet 번호(패킷 당 번호)가 아니다.
- 보통 Seq #는 Segment의 첫 번째 Byte Number를 의미한다. (Byte값과 Byte Number는 다른 개념이다.)
- TCP에서는 Sender에서 Receiver까지 패킷들이 순서대로 전달되는 형태를 Byte Stream이라 비유한다.
(순서대로 전송되는 형태를 In-Band 전송이라 부른다.)
- 특히, Numbering System은 제일 처음 전송되는 패킷의 Seq #을 정하는 체계이다.
- 보안상의 이유로, 처음 패킷의 Seq #은 Random하게 선정한다.
Example 15.1 (TCP/IP Protocol Suite p.437)
TCP Connection에서 5,000Byte의 파일을 5개의 Segment로 전송하고자 한다.
첫 번째 Byte의 Seq #이 10,001번으로 정해졌다고 한다.
이 때, 각 Segment의 Seq #은 어떻게 되는가
sol)
- 각 Segment 당, 1,000Byte로 구성된다.
- 즉, 각 Segment의 Seq #는 10,001 - 11,001 - 12,001 - 13,001 - 14,001 이다.
- 전체 Byte Stream Number의 첫 번째 값인 10,001은 Random하게 계산된 결과일 것이다.
※ 각 Seq #들은 해당 Segment를 이루는 Byte Stream 중 첫 번재 Byte Number 이다.
ACK Number
- Segment의 Acknowledgment Field에 저장되는 값 중 하나이다.
- 1번 패킷이 도착했다는 신호를 알리기 위한 ACK 번호로 2가 설정되는 메커니즘이다.
- 즉, 다음으로 받아야 할 패킷의 Byte 번호를 보내는 방식으로 패킷 수신에 성공했음을 알리는 방법이다.
- ACK Number는 Cumulative(누적)된다.
※ TCP에서는 ACK의 개수를 줄이기 위해, 통상 패킷 두 개당 하나의 ACK을 보내게 한다.
- ACK Number: 13,001는 11,001 ~ 13,000까지 두 Segment에 대한 수신에 성공했음을 한꺼번에 알리는 ACK이다.
- 즉, ACK: n 은 n-1번 Byte Number 까지 수신에 성공했음을 의미한다.
(위와 같은 이유로, ACK Number가 Cumulative하다고 표현하는 것이다.)
TCP Connection : Three-Way Handshaking
1. Connection Establishment
- Clien-Server 환경에서 제일 먼저, Server가 Passive Open되고, 접속자(Client)를 기다린다.
1st Packet (SYN)
- Active Open한 Client는 서버에게 Seq # 8,000번의 SYN를 보낸다.
- 실제로, SYN 메시지에는 데이터가 포함되어 있지 않지만 하나의 Seq #가 할당된다.
2nd Packet (SYN + ACK)
- Server는 Seq # 15,000번의 ACK 신호(8,001)를 전송하여 8,000까지의 Byte Number에 해당하는 패킷까지 수신했음을 알린다.
(Seq #이 15,000으로 시작했으므로, 다음 Data Transfer 절차에서는 15,001로 시작된다.)
- SYN + ACK 메시지또한 데이터가 포함되어 있지 않지만 하나의 Seq #가 할당된다.
- ACK 메시지에는 수신자의 Window 크기 정보(rwnd)까지 전송된다. (흐름 제공 방법)
- 즉, rwnd: 5,000은 수신자가 5,000 Byte까지 받을 여유(가용 수신 버퍼)가 있음을 의미한다.
(또한, 그림의 경우에서 rwnd의 초기값은 5,000임을 알 수 있다.)
3rd Packet (ACK)
- 그림의 상황에서는 3번째 패킷이 두 번째 패킷의 메시지( Seq # 15,000)에 해한 ACK를 보내야 한다.
- ACK 패킷은 데이터를 포함하고 있지도 않으며, Seq #를 할당받지도 않는다.
- 첫 번째 패킷과 동일하게, 세번째 패킷 또한 Seq #이 8,000이다.
- 세 번째 패킷과 첫 번째 패킷의 Seq #이 같은 것을 확인할 수 있는데, 이는 세 번째 패킷이 ACK로만 구성되어 있는 ACK 메시지이기 때문이다.
(ACK 메시지의 Seq #은 가장 최근에 전달받았던 ACK 값에 1을 뺀 값으로 설정하여 데이터를 담고 있지 않음을 분명히 한다.)
2. Data Transfer
- 데이터를 주고받는 절차이다.
- Seq # 8,000번은 이전 절차의 SYN 메시지에 할당되었으므로, Data Transfer 절차에서는 Seq # 8,001번 부터 사용된다.
- Connection Establishment 절차 이후에, 수신한 메시지가 없으므로 ACK값은 15,001로 그대로 유지한다.
- A는 ACK Flag이다.
- P는 Push Flag로, 논외로 간주한다. (시스템만이 제어할 수 있다.)
- TCP에서는 하나의 패킷에 하나의 ACK가 아닌, 다수의 패킷에 하나의 ACK를 보내는 것을 지향하므로, 2 개의 패킷을 수신하면 하나의 ACK를 전송한다.
- 마침, ACK에 보낼 데이터까지 있는 경우, ACK 메시지에 데이터까지 담아서 전송한다.
- 그림에서, 서버가 클라이언트에게 보내는 메시지에는 rwnd 값이 누락되어 있다. (가용 수신 버퍼의 크기까지 클라이언트에게 알려주어야 한다.)
- Connection Establishment 절차에서 클라이언트의 rwnd 값은 10,000이라 서버에게 알렸다. 그 이후 서버는 2,000Byte의 데이터를 전송했음에도 불구하고 바로 다음 ACK 메시지에서도 rwnd 값을 10,000이라고 서버에 알렸다.
이는 클라이언트가 서버로 부터 수신한 2,000bytes의 데이터를 수신한 즉시 Process가 사용해서 버퍼가 또 빈 상태가 되었음을 의미한다.
3. Connection Termination
- 클라이언트가 먼저 Termination을 진행(제안)하는 예시이다.
- 클라이언트가 작업을 마치기 위해 Active Close를 함과 동시에 Socket을 Close하기 위한 FIN 메시지를 서버에 송신한다.
(FIN 메시지 또한 ACK 메시지처럼 데이터를 담고 있지는 않으나, Seq #을 1만큼 차지한다.)
(Seq #이 x인 것의 의미는, 가장 마지막으로 보낸 메시지의 Byte Number가 x-1이었음을 의미한다.)
- FIN 메시지를 수신한 서버는 Passive Close를 함과 동시에 FIN + ACK 메시지를 클라이언트에게 송신한다.
- 마지막으로 클라이언트가 ACK 메시지를 서버에게 보낸 후 끝마친다.
(ACK 메시지의 Seq #은 가장 마지막으로 받았던 ACK의 번호에 1을 뺀값으로 설정한다.)
※ Three-Way Handshaking에서는 클라이언트와 서버가 동시에 연결을 종료시킨다.
A TCP Connection : Half Close
- 클라이언트에서 서버측에 보낼 데이터를 한꺼번에 다 보낸 후, FIN 메시지를 보내어 서버로의 Connection을 종료한다.
(단, Connection이 종료되어도, ACK 메시지는 보낼 수 있다.)
- 단, 서버에서는 보낼 메시지가 있으므로, ACK + FIN이 아닌, ACK 메시지만 전송하여 클라이언트로의 Connection을 유지한다.
- 그 이후, 서버는 보낼 메시지를 클라이언트에게 다 보낸 후, FIN 메시지를 전송하여 클라이언트로의 Connecion을 종료한다.
- 서버로부터 FIN 메시지를 수신한 클라이언트는 ACK 메시지를 전송한다.
(Connection이 종료된 이후에도 ACK 메시지는 전송할 수 있다.)
※ ACK 메시지의 Seq #은 가장 마지막으로 수신한 메시지의 ACK 값에 1을 뺀 값임을 명심하자
※ Half Close 에서는 클라이언트와 서버가 따로 연결을 종료시킨다.
Half Close 사용 예시
\(\texttt{sun > rsh bsdi sort < datafile}\)
- 위 명령어를 UNIX 기반 SUN Machine에서 실행한 예시이다.
- \(\texttt{rsh}\) : Remote Shell이라는 뜻으로, 다른 머신에서 명령을 수행할 것을 명령한다.
- 즉 SUN 머신에서 bsdi 머신에게 Sort 작업을 대신할 것을 명령하는 것이다.
- stdin은 datafile로 Redirection 되어있다.
- stdout은 Terminal에 연결되어 있다. (Default Setting)
- Sort를 위해서는 모든 데이터를 보유하고 있어야 하므로 SUN 머신으로부터 모든 데이터를 일방적으로 받기만 한다.
- SUN 머신은 정렬 대상 데이터를 모두 전송한 후, FIN 메시지를 보내어 Half Close 방식으로 Connection Termination 한다.
- EOF까지 수신한 bsdi는 정렬을 수행한 이후, 정렬 결과를 SUN 머신에게 전송한 후, FIN 메시지를 보낸다.
- SUN 머신은 bsdi에게 ACK 메시지를 보낸다.
State Transition Diagram (Finite State Machine)
- 통신 프로토콜(S/W)을 모델링하는 수단이다.
- Finite State Machine에서 Edge에 쓰여있는 정보는 "(Event) / (Action)" 형태로 표기한다.
- 3-Way Handshake Connection에서 일어날 수 있는 여러 시나리오들을 State Transition Diagram으로 표현한 예시이다.
Example. 3-Way Handshake Connection Establishment를 State Transition Diagram으로 해석한 예시
- 클라이언트/서버는 모두 처음에 Closed 상태에 있다.
- 서버는 시스템으로부터 Passive open event가 발생되어 클라이언트로 부터의 메시지를 기다리는 LISTEN state에 들어간다.
- 클라이언트는 Active open event가 발생되어 서버에게 SYN를 전송하여 SYN-SENT state에 들어간다.
- SYN를 수신한 서버는 SYN+ACK를 전송한 후, SYN-RCVD state에 들어간다.
- SYN+ACAK를 수신한 클라이언트는 ACK를 전송한 후, ESTABLISHED state로 들어간다.
- ACK를 수신한 서버는 ESTABLISHED state로 들어가 클라이언트와 Data Transfer를 진행한다.
Example. Half Close를 State Transition Diagram으로 해석한 예시
- 클라이언트와 서버 모두 ESTABLISHMENT state에 들어있는 상태에서 시작한다.
- 클라이언트에 Close event가 발생되어 FIN을 서버에게 전송한 후, FIN-WAIT-1 state에 들어간다.
- FIN을 수신한 서버는 ACK를 전송한 후, CLOSE-WAIT state에 들어간다. (즉, Half Close 상태에 돌입하여 서버만 클라이언트에게 메시지를 전송할 수 있는 상태가 된다.)
- ACK를 수신한 클라이언트는 아무 Action을 취하지 않은 채(-) FIN-WAIT-2 state 에 들어간다.
- 데이터를 모두 전송한 서버(Close event)가 클라이언트에게 FIN을 전송한다.
- FIN을 수신한 클라이언트가 ACK를 전송하며 TIME-WAIT state에 들어간다.
- TIME-WAIT state가 존재하는 이유는, ACK를 수신하자마자 바로 연결을 종료하는 것이 아니라 일정 시간동안 특별한 event를 기다려 보고 아무런 event가 발생되지 않은 경우에 종료하기 위함이다.
※ ESTABLISHMENT state는 실제로 복잡한 작업을 수행하는 하나의 Finite State Machine이지만, 하나의 state로 추상화한 것이다. (이러한 State를 Super State라 표현하다.)
Time-Line Diagram : Connection Establishment & Half Close Termination
- 클라이언트-서버 환경에서 3-Way Handshake 방법으로 Connection Esthblishment하며, Half Close 방법으로 Connection Termination하는 예시이다.
- 서버가 먼저 Passive-Open하여 LISTEN 상태에 들어간다.
- Active-Open한 클라이언트가 서버에게 SYN를 보낸 후, SYN-SENT 상태에 들어간다.
- SYN를 수신한 서버는 SYN+ACK를 보내고 SYN-RCVD 상태에 들어간다.
- SYN+ACK를 수신한 클라이언트는 ACK를 보낸 후, ESTABLISHMENT 상태에 들어간다.
- ACK를 수신한 서버 또한 ESTABLISHMENT 상태에 들어간다.
- Data Transfer를 마친 클라이언트는 Active Close하여 FIN을 서버에 보낸 후, FIN-WAIT-1 상태에 들어간다.
(클라이언트가 일방적으로 연결을 마친 Half Close 형태이다.)
- FIN을 수신한 서버는 ACK를 보낸 후, CLOSE-WAIT 상태에 들어간다.
- CLOSE-WAIT 상태에서 서버는 못다한 데이터 전송을 수행한다.
- ACK를 수신한 클라이언트는 FIN-WAIT-2 상태에 들어가서 서버로부터 데이터를 받기만 한다.
(Half Close 상태, 클라이언트는 서버에게 ACK만 보낼 수 있다.)
- 데이터 전송을 끝마친 서버(Passive Close)는 클라이언트에게 FIN을 전송하고 LAST-ACK 상태에 들어간다.
- FIN을 수신한 클라이언트는 ACK를 보내며 TIME-WAIT상태에 들어간 후, 즉시 CLOSED 상태에 들어가지 않고, 2MSL* timer가 만료될 때 까지 대기한다.
(CLOSED 이전에 예상치 못한 이벤트에 대응하기 위한 시간이다. 가령, 서버가 CLOSED되기 위한 ACK의 누락같은 상황이 예상치 못한 이벤트에 속한다. 서버 또한, FIN 보낸 후 타이머를 동작시켜서 제한 시간내에 ACK가 도착하지 않으면 FIN을 다시 전송하는 메커니즘을 보유하고 있다.)
- ACK를 수신한 서버는 CLOSED 상태에 들어가고, 2MSL timer가 만료되면 클라이언트 또한 CLOSED 상태에 들어간다.
(2MSL timer가 만료되기 까지 아무 이벤트가 발생되지 않으면 아무런 문제가 없다 간주하고 클라이언트 또한 CLOSED 상태에 들어가게 된다.)
* 2MSL : Double Maximum Segment Lifetime
- MSL은 SEgment가 네트워크 상태에 존재할 수 있는 최대 시간이다.
- 보통 MSL은 30초에서 1분 사잇값이므로, 2MSL은 1분에서 2분 사이의 값이다.
(네트워크상에서 1분은 굉장히 긴 시간이다. 보통 트래픽이 많지 않은 상황에서 지구 반대편으로 메시지를 전달하는데 소요되는 시간은 100ms 수준이다. 즉, 클라이언트는 꽤 오랜 시간을 대기하여 안정성을 높이는 것이다.)
Time-Line Diagram : Simultaneous Open
- 3-Way Handshake Protocol에서는 한 쪽이 먼저 Active Open하면 다른 한 쪽이 Passive-Open하는 형태로 이루어졌다.
- Peer to Peer 환경(파일공유 시스템 등)에서는 양 측 모두 서버인 동시에 클라이언트가 될 수 있으므로, 양쪽에 동시에 SYN가 전송될 수도 있다.
- SYN를 보낸후 SYN+ACK를 대기하고 있는데, SYN가 수신됨을 통해 Simultaneous 환경임을 감지할 수 있다.
- SYN+ACK를 수신한 노드는 ESTABLISHED 상태에 들어가서 Data Transfer를 준비한다.
Time-Line Diagram : Simultaneous Close
- 보통 클라이언트-서버 환경에서는 Termination을 진행하는 주체가 경우에 따라 다르다.
ex) 클라이언트가 웹서버로 부터 파일을 다운로드 받는 경우엔 서버가 먼저 Termination을 진행한다.
ex) 클라이언트가 웹서버에 파일을 업로드하는 경우엔 클라이언트가 먼저 Termination을 진행한다.
- Peer to Peer 환경에서는 그림과 같이 동시에 Termination을 진행하는 것이 가능하다.
- 마찬가지로, FIN를 전송했는데 FIN+ACK 대신, FIN를 수신함을 통해 Simultaneous 환경임을 감지한다.
- Simultaneous Close 환경에서도 ACK를 수신한 이후 2MSL timer가 만료될 때 까지 CLOSED 상태에 들어가지 않는다.
Time-Line Diagram : Denying a Connection
- 정상 종료시에는 FIN Flag를 사용하며, 비정상 종료시에는 RST(Reset) Flag를 사용한다.
- RST를 송수신하게 되면 그 즉시 CLOSED 상태에 들어간다. (그 즉시 종료된다.)
Time-Line Diagram : Aborting a Connection
- 정상적인 통신 중에 종료되는 예시이다.
- 시스템에서 Abrot Event(Interrupt)가 발생되면, RST + ACK를 송신한 후, 송수신 Buffer를 모두 초기화한 후 CLOSED 상태에 들어간다.
- RST+ACK를 수신한 주체 또한, 송수신 Buffer를 모두 초기화한 후, 시스템에 Error event를 알린 후, CLOSED 상태에 들어간다.
Window Mechanism in TCP
- TCP에서는 Windows 개념을 Flow Control, Error Control, Congestion Control에 이용한다.
- Full-Duplex 통신 상황에서 A가 B에게 메시지를 전송할 때, A에는 Send Window가 존재하며, B에는 Receive Window가 존재한다.
- 반대로, B가 A에게 메시지를 전송할 때, B에는 Send Window가, A에는 Receive Window가 존재한다.
- 결국 Full-Duplex 통신을 구현하기 위해서는 4개의 Windows가 요구된다.
- 간결한 설명을 위해 본 포스트에서는 단방향 통신을 전제로 설명을 진행한다.
- Full-Duplex는 단 방향 통신에서의 개념을 양 쪽 모두에게 적용하면 된다. (다른 부가사항이 없다.)
1. Send Window (송신 창)
- Send Window는 보낼 수 있는 메시지의 양을 의미한다.
- 위 그림은 Byte Number 201부터 300까지 전송 가능함을 표현한 것이다.
- Send Window의 크기는 수신자가 결정한다.
- 수신자는 ACK Number와 rwnd로 구성된 ACK를 송신자에게 전송한다.
- ACK Number를 Window의 첫 번째 Byte Number(First Outstanding Byte, \(S_{f}\))로 설정한다.
- rwnd를 통해 Window의 크기를 결정한다. (rwnd는 수신자의 가용 Buffer 크기이다.)
- Send Window 왼편에 위치한 Byte Number들은 송신에 성공했고 그에 따른 ACK까지 다 받은 상태의 데이터들이다. (더 이상 필요가 없으므로 Buffer에서 지운다.)
Outstanding Bytes (분홍색 Byte Numbers, 201 ~ 260)
- 전송했지만, 해당 ACK를 수신하지 못한 데이터들을 의미한다.
- Outstanding Bytes들은 재전송에 대비하여, ACK를 수신하기 전까지 유지된다.
※ "Outstanding"은 "훌륭한"이라는 의미 외에 "아직 해결되지 않은"의 의미도 있다.
Bytes that can be sent (흰색 Byte Numbers, 261 ~ 300)
- 전송 가능한 공간을 의미한다.
- 응용 프로세스가 이미 데이터를 입력했을 가능성도 잔재하는 공간이다.
- Send Window의 Left Wall과 Right Wall은 가변적이다.(움직일 수 있다.)
- Left Wall은 수신한 ACK Number에 의해 결정된다.
(만약 261번 ACK Number를 수신했다면, Left Wall이 260번 데이터의 오른쪽에 위치하여 그 이전 데이터들은 다 지워진다.)
- Right Wall은 수신자의 Window 크기(가용 Buffer 크기, rwnd에 의해 결정된다.
- Right Wall은 왼쪽으로 움직일 수 없다.
(즉, Right Wall이 오른쪽으로 움직이며 Send Window의 크기를 늘릴 수는 있으나, 왼쪽으로 움직여 Window의 크기를 줄일 수는 없다. 크기를 줄이는 건 Left Wall의 역할이다.)
2. Receive Window (수신 창)
- Receive Window가 생성되기 이전에 Receive Buffer가 있었을 것이다.
- 위 그림에는 100Bytes의 Receive Buffer(Allocated Buffer)가 위치해있다.
- Allocated Buffer의 크기는 변하지 않는다.
- Allocated Buffer의 왼편에 분홍색 영역에는 수신자로 부터 전달받아 이에 대한 ACK를 송신자에게 보냈으며, 응용 프로세스가 아직 사용하지 않은 데이터들이 속한다.
- Receive Window Size(rwnd)는 비어있는 Window의 크기를 의미하며, 곧 Sender로 부터 데이터를 받을 수 있는 공간을 의미한다.
- rwnd는 ACK에 포함되어 전송되며, Send Window의 Right Wall의 위치를 결정짓는 역할을 한다.
- Application이 201 ~ 260까지의 데이터를 읽어가면, Receive Window의 Right Wall은 60만큼 오른쪽으로 이동하여 Receive Window의 크기를 유지한다.
(즉, Receive Window는 261 ~ 360의 영역을 보유하고 있게 된다.)
- 즉, Receive Window의 Right Wall은 Application이 읽어 간 데이터의 수 만큼 오른쪽으로 이동한다.
- Receive Window의 Left Wall은 수신한 데이터의 수만큼 오른쪽으로 이동한다. (ACK를 보낸 후 이동한다.)
TCP Timers
- TCP에는 네트워크 서비스에 이용되는 5가지 타이머가 존재한다.
1. Retransmission Timer (재전송 타이머)
- 송신자측에서 유지하는 타이머이다.
- 재전송 타이머에서는 Time-Out Interval을 계산하기 위해 아래와 같은 Factor를 이용한다.
\(RTT_{M}\): Measured RTT (측정된 RTT)
\(RTT_{S}\): Smoothed RTT (측정된 RTT의 평균치)
\(RTT_{D}\): RTT Deviation (RTT의 편차)
- 재전송 타이머에서의 Time-Out은 \(RTT_{S}\)와 \(RTT_{D}\)를 인자로 사용한다.
- RTO Time-Out 기준값(만료 시간)을 산정할 때 편차까지 고려하는 이유는 아래에서 설명한다.
1) RTT의 평균은 같으나 RTT의 편차가 작은 Case
- 2)번 케이스보다 상대적으로 RTO Time-Out 기준값이 평균값에 가깞게 책정된다.
2) RTT의 평균은 같으나 RTT의 편차가 큰 Case
- 1)번 케이스보다 상대적으로 RTO Time-Out 기준값이 평균값보다 크게 책정된다.
※ TCP에서는 Time-Out이 발생하면 심각한 성능저하가 일어나므로, Time-Out의 발생을 최대한 지양한다.
Computation: \(RTT_{S}\)
- 초기화 값: 값 없음
- 첫 번째 RTT 측정 직후: \(RTT_{S} = RTT_{M}\)
(평균을 계산할 데이터가 초기값 하나 뿐이기 때문이다.)
- 이후 RTT 측정: \(RTT_{S} = (1-\alpha) * RTT_{S} + \alpha * RTT_{M}\)
(이전 Stage까지 계산된 \(RTT_{S}\)와 현재 \(RTT_{M}\) 간의 Weighted Sum)
(\(\alpha\) = 현재까지 측정된 값들에 대한 History를 통해 산정되는 상수, 일반적으로 \({1 \over 8}\) 수준이다.)
Computation: \(RTT_{D}\)
- 초기화 값: 값 없음
- 첫 번째 RTT 측정 직후: \(RTT_{D} = {RTT_{M} \over 2}\)
(평균을 계산할 데이터가 초기값 하나 뿐이기 때문이다.)
- 이후 RTT 측정: \(RTT_{D} = (1-\beta) * RTT_{D} + \beta * |RTT_{S} - RTT_{M}|\)
(\(\beta\) = 상수, 일반적으로 \({1 \over 4}\) 수준이다.)
(과거의 편차와 현재의 편차의 Weighted Sum이다. \(RTT_{D}\)는 과거의 편차, \(|RTT_{S} - RTT_{M}|\)은 현재의 편차를 의미한다.)
Computation: RTO
- 초기에는 초기값을 그대로 둔다.
- \(RTO = RTT_{S} + 4 * RTT_{D}\)
(평균값에 4배의 편차를 더하여 구한다.)
Example 15.3 (TCP/IP Protocol Suite p.480)
- 3-Way Handshake로 연결이 이루어진 상태에서, RTO값이 계산되는 예시이다.
- 처음에는 보유한 Factor 값이 아무것도 없으므로, RTO = 6.00으로 보수적으로 설정한다.
- SYN를 보내고 SYN+ACK를 받기 까지 1.50s가 소요되었다면,
RTT_{M} = 1.5 (첫 번째 측정값)
RTT_{S} = 1.5 ((첫 번째 측정이 이루어졌을 때, 평균값은 곧 첫 번째 측정값이다.
RTT_{D} = 0.75 (첫 번째 RTT 측정 이후 편차값은 첫 번째 측정값의 \({1 \over 2}\)수준)
RTO = 1.5 + 4 * 0.75 = 4.5
- 2개의 Segment를 전송하고, 그에 대한 ACK를 받기 까지 2.50s가 소요되었다면,
\(RTT_{M} = 2.5\) (이후 측정값)
\(RTT_{S} = (1-{1 \over 8}) * 1.5 + {1 \over 8} * 2.5 = 1.625\)(이후 측정값)
\(RTT_{D} = (1-{1 \over 4}) * 0.75 + {1 \over 4} * |1.625 - 2.5| = 0.78\) (이후 측정값)
RTO = 1.625 + 4 * 0.78 = 4.74 (\(RTT_{M}\)이 증가된것이 반영되어 RTO 값 또한 증가했음을 확인할 수 있다.)
Example 15.4 (TCP/IP Protocol Suite p.481)
- TCP에서 패킷을 보냈는데 Time-Out이 발생한 경우, 재전송하고 ACK까지 받았다면 RTT_{M}값을 새로 측정하지 않는다.
- 패킷을 보낸 후, Time-Out이 발생하여 재전송하고난 뒤애 수신한 ACK는 첫 번째 패킷에 대한 ACK인지, 재전송한 패킷에 대한 ACK인지를 확인할 방법이 없기 때문이다.
Exponential Backoff of RTO: 재전송을 한 경우, RTT를 새로 측정하지 않고 RTO Time-Out Interval을 두 배로 증가시킨다. (4.74 -> 9.48, 만약 또 다시 Time-Out이 발생되면 증가된 값에 다시 두 배를 취한다. (9.48 -> 18.96))
- RTO가 두 배가 된 채로 패킷(Seq # 1701)을 전송하고 정상적으로 ACK를 받았다면, \(RTT_{M}\)을 측정하여 \(RTT_{S}\) 와 \(RTT_{D}\)를 새로 계산하여 RTO값을 갱신한다. (4.74 -> 6.34로 이전보다 증가했음을 알 수 있다.)
※ 재전송을 한 경우에는 RTT를 새로 측정하지 않고, RTO를 두 배로 증가시킨다.
2. Persistence Timer (영속 타이머)
- 수신자가 rwnd = 0임을 통보한 후, Window Size를 일정량 회복시켜 가용할 수 있음을 알리는 패킷을 보냈으나 이 패킷이 Lost되어 Deadlock이 발생하는 것을 방지하고자 사용하는 타이머이다.
- 송신자는 수신자로부터 rwnd = 0임을 알리는 패킷을 받으면, 영속 타이머를 Start한다.
- 영속 타이머에 Time-Out이 발생하면, 송신자는 수신자에게 Probe Signal을 보내어 아직도 rwnd = 0인지를 확인한다.
- Probe Signal을 받은 수신자는 자신의 rwnd를 알리는 패킷을 송신자에게 보낸다.
3. Keepalive Timer
- Server와 Clien간의 Connection이 오랫동안 Idle 상태에 있는 것을 방지하기 위한 타이머이다.
(오랫동안 Idle상태를 유지했음의 의미는, 서로 아무런 패킷을 주고받지 않았거나, 어느 한 쪽의 연결이 도중에 끊겼는데, 상대는 그 사실을 모르는 상태를 의미한다.)
- Server에서 유지하는 타이머로, Client로부터 Segment를 받을 때 마다 초기화한다.
- 2시간이 경과해 Time-Out이 발생하면, 75초 간격으로 Client에게 10개의 Probe Signal을 전송한다.
- Client로부터 Probe Signal에 대한 응답이 없으면 Down State로 간주하고 연결을 종료한다.
4. Time-Wait Timer (시간 대기 타이머)
- TCP에서 Connection을 종료(3-Way Handshake, Simultaneous Close, Half Close 등)하는 동안에 사용하는 타이머이다.
- 마지막으로 연결을 끝내는 패킷(보통 ACK)을 보낸 후, 시간 대기 타이머를 Start한다.
- 시간 대기 타이머(1분~2분)*가 Time-Out되는 동안, 아무런 패킷을 받지 못했다면, 정상적으로 연결이 종료되었다 간주하고 최종적으로 연결을 종료한다.
* 네트워크에서 패킷이 존재할 수 있는 최대 시간을 1분 내지 2분으로 산정한다.
5. ACK Delaying Timer
- 수신자측에서 유지하는 타이머이다.
Reference: TCP/IP Protocol Suite 4th Edition
(Behrouz A. Forouzan 저, McGraw-Hill, 2010)
Reference: Data Communications and Networking 5th Edition
(Behrouz A. Forouzan 저, McGraw-Hill, 2012)