
TCP에서 "연결"은 회선을 잡아두는 것이 아닙니다. 인터넷은 packet switching이고 코어는 아무 자리도 예약해주지 않습니다. 연결은 오직 양 끝 호스트의 메모리에만 존재합니다.
연결을 연다는 것은 구체적으로 다음을 맞추는 일입니다.
이 정보를 담은 커널 내부 자료구조가 3편에서 본 4-tuple로 식별되는 소켓의 실체입니다.

세 단계 각각이 하는 일이 다릅니다.
ISN을 0부터 시작하지 않고 난수로 잡는 점이 중요합니다. 같은 4-tuple로 연결을 다시 맺었을 때, 이전 연결의 늦게 도착한 세그먼트가 새 연결의 데이터로 오인되는 것을 막기 위해서입니다.
왜 두 번으로는 안 되는지도 같은 맥락입니다. 양쪽이 각자의 ISN을 보내고 각자 확인받아야 하므로 최소 네 번의 교환이 필요한데, 서버의 ACK와 SYN을 한 세그먼트에 합칠 수 있어 세 번이 됩니다.
4편의 헤더 표에서 한 줄로 넘어갔던 flags를 여기서 풀면 다음과 같습니다.
| flag | 의미 | 쓰이는 곳 |
|---|---|---|
| SYN | 연결을 시작하고 ISN을 동기화 | handshake의 앞 두 세그먼트에만 |
| ACK | acknowledgment number 필드가 유효함 | 연결 수립 후 거의 모든 세그먼트 |
| FIN | 더 보낼 데이터가 없음 | 연결 종료 |
| RST | 연결을 즉시 끊음 | 닫힌 포트로 접속 시도 등 비정상 상황 |
종료는 한쪽이 먼저 끝낸다고 선언하는 것에서 시작합니다.
TCP가 full duplex라 방향이 둘이고, 각 방향을 독립적으로 닫기 때문에 네 단계가 됩니다. 한쪽만 닫힌 상태를 half-close라고 부릅니다. 연결 수립에서는 서버의 ACK와 SYN을 합칠 수 있었지만, 종료에서는 2번과 3번 사이에 남은 데이터를 보낼 시간이 필요해 합쳐지지 않는 것이 일반적입니다.

먼저 FIN을 보낸 쪽은 마지막 ACK를 보낸 뒤 바로 사라지지 않고 TIME_WAIT 상태로 일정 시간 머뭅니다. 기다리는 시간은 MSL(Maximum Segment Lifetime, 세그먼트 최대 생존 시간)의 두 배입니다.
이유는 두 가지입니다. 첫째, 마지막 ACK가 유실되면 상대는 FIN을 재전송하는데, 이미 소켓을 지워버렸다면 응답할 주체가 없습니다. 둘째, 네트워크 어딘가에서 헤매던 옛 세그먼트가 뒤늦게 도착해 같은 4-tuple의 새 연결을 오염시키는 것을 막습니다. 왕복 한 번 분량을 기다려 그런 세그먼트가 전부 소멸하기를 보장하는 것입니다.