TCP
TCP(Transmission Control Protocol)란, 두 네트워크 호스트간 전송하는 패킷의 순서를 보장하는 전송제어 프로토콜이다. 주로 IP와 함께 사용되어, TCP/IP 프로토콜로 두 네트워크 호스트의 통신을 담당한다.
TCP는 1:1로 통신하는데, 연결을 수립할 때는 3-way handshake로, 해제할 때는 4-way handshake로 해제한다.
또한, TCP는 여러 프로토콜의 기반이 되기도 하는데, 가령 TCP 기반의 HTTPS 프로토콜의 경우 TCP의 3-way handshake로 연결을 수립한 다음, HTTPS의 SSL handshake가 이루어진다.
TCP Segments
TCP 세션으로 연결된 양 끝단 간에 서로 교환 및 전달되는 데이터 단위이다. TCP Header와 Packet(Data)으로 구성된다. (참고로 UDP의 경우, UDP Segment가 아닌, UDP Datagram이라 표현한다)
TCP Header
RFC 9293에서 다음과 같이 TCP Header의 구조를 보여주고 있다.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Rsrvd |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| [Options] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :
: Data :
: |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
위 그림에서 한 tick은 1 bit
를 의미한다. 따라서 다음과 같이 구성됨을 알 수 있다.
- Source Port:
16 bits
- Destination Port:
16 bits
- Seqeunce Number:
32 bits
- Acknowledgment Number:
32 bits
- Data Offset(a.k.a. DOffset):
4 bits
- Control Bits(a.k.a. flags):
8 bits
- Window:
16 bits
- Checksum:
16 bits
- Urgent Pointer:
16 bits
- Options:
size(Options) == (DOffset-5)*32 bits
- DOffset 값이 5보다 클 경우에만 존재한다.
- Data: 데이터 크기에 따라 가변적이다.
3-way handshake / 4-way handshake
두 단말기(End-point 또는 Host) 사이에서 다음과 같이 연결을 수립하고 해제한다.
이를 자세히 살펴보면 연결 수립과정은 다음과 같다.
참고로 연결 수립은 어느 쪽에서 먼저 요청해도 되지만, Client에서 Server로 연결 수립을 요청한다고 가정한다.
TCP Peer A TCP Peer B
1. CLOSED LISTEN
2. SYN-SENT --> <SEQ=100><CTL=SYN> --> SYN-RECEIVED
3. ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
4. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK> --> ESTABLISHED
5. ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED
Sequence Number(seq
)는 임의로 생성한 난수로, Client에서 SYN
flag와 함께 전송한다. 그리고 Client는 SYN-SENT
상태가 된다.
Server가 패킷을 받고 나면, 전달받은 seq
값에 +1
한 값을 Acknowledgment Number(ack
)로 만든다. 그리고 Server 또한 임의의 난수(seq
)를 만들고 이를 SYN
, ACK
flag, ack
응답값 모두를 Client에 전송한다. 그리고 서버는 SYN-RECEIVED
상태가 된다.
마찬가지로 Client 또한 Server로부터 전달받은 seq
값에 +1
한 값을 ack
응답값으로 해 Server에 전달한다. 그리고 Client는 ESTABLISHED
상태가 된다.
Server에서 ack
값을 받으면 마찬가지로 ESTABLISHED
상태가 된다.
연결 해제 과정을 자세히 보면 다음과 같다.
참고로 연결 해제 또한 어느 쪽에서 먼저 요청해도 되지만, Client에서 Server로 연결 해제를 요청한다고 가정한다.
TCP Peer A (Client) TCP Peer B (Server)
1. ESTABLISHED ESTABLISHED
2. (Close)
FIN-WAIT-1 --> <SEQ=100><ACK=300><CTL=FIN,ACK> --> CLOSE-WAIT
3. FIN-WAIT-2 <-- <SEQ=300><ACK=101><CTL=ACK> <-- CLOSE-WAIT
4. (Close)
TIME-WAIT <-- <SEQ=300><ACK=101><CTL=FIN,ACK> <-- LAST-ACK
5. TIME-WAIT --> <SEQ=101><ACK=301><CTL=ACK> --> CLOSED
6. (2 MSL)
CLOSED
Client가 연결을 종료하기위해 FIN
flag와 함께 seq
값을 보낸다. 그리고 Client는 FIN-WAIT-1
상태가 된다.
Server는 seq
값에 +1
한 값을 ack
값으로 해서 ACK
flag와 함께 Client에 전달한다. 그리고 CLOSE-WAIT
상태가 된다.
이때, Client는 FIN-WAIT-2
상태가 되며 여전히 Server로부터 FIN
flag를 기다리고 있다.
Server는 seq
를 생성해서 Client에 전달한다. 그리고 LAST-ACK
상태가 된다.
Client는 서버로부터 받은 seq
값에 +1
한 값을 ack
값으로 해서, ACK
flag와 함께 전달한다. 그리고 TIME-WAIT
상태가 된다. 이때 TIME-WAIT
은, 먼저 연결을 종료하는 쪽에 생성되는 소켓으로 혹시 모를 패킷 전송 실패에 대비하기 위해 존재한다.
Server는 Client로부터 ack
를 받은 다음, CLOSED
상태가 된다.
Client는 Server의 최대 세그먼트 수명(MSL)의 2배를 기다린 다음, CLOSED
상태로 바뀌며 연결이 종료된다.
몇 가지 궁금증
왜 무작위 Sequence Number를 보낼까?
Connection에 사용되는 포트는 유한하고, 시간이 지나면 재사용 된다. 그래서 이전에 사용된 포트번호를 사용할 가능성이 있기 때문에 무작위 숫자를 사용한다.