4-way Handshake
Last updated
Last updated
TCP 프로토콜이 3 way handshake를 통해 연결을 수립하였다면 연결 해제는 4 way handshake를 사용한다.
[Step1]
클라이언트가 연결 해제 요청 FIN을 서버로 전송한다.
클라이언트 상태: ESTABLISHED -> FIN_WAIT_1
[Step2]
서버는 연결 해제 요청을 승인한다는 의미로 클라이언트에 ACK을 전송한다.
연결 해제 요청에 대한 승인으로, 바로 해제 되는 것이 아닌, CLOSE_WAIT
상태로 진입한 후 연결 해제 준비를 한다.
서버 상태: ESTABLISHED -> CLOSE_WAIT
클라이언트 상태: FIN_WAIT_1 -> FIN_WAIT_2
Close-Wait
상태 후 애플리케이션이 종료됬다면 다음 단계로 넘어간다.
[Step3]
서버는 연결 해제 준비가 완료되었다는 FIN을 클라이언트로 전송한다.
서버 상태: CLOSE_WAIT -> LAST_ACK
클라이언트 상태: FIN_WAIT_2 -> TIME_WAIT
[Step4]
클라이언트는 TIME_WAIT 시간 만큼 대기 후 서버로 ACK을 전송함으로써 마침내 연결이 해제된다.대개의 경우 2MSL(maximum segment lifetime - 1분~4분) 동안 TIME_WAIT 상태로 대기한다.
클라이언트는 연결을 해제하겠다는 ACK을 바로 서버로 보내는 대신 2MSL 동안 TIMW_WAIT 상태로 대기함으로써 서버는 아직 도착하지 못한 패킷들을 받을 수 있는 여유 시간이 생긴다.
클라이언트 상태: TIME_WAIT -> CLOSED
서버 상태: LAST_ACK -> CLOSED
클라이언트의 데이터 전송이 끝났더라도, 서버에서는 데이터를 전송하고 있을수 있기 때문이다. 클라이언트의 데이터 전송 종료(Step1)에 해당하는 FIN의 응답으로 서버에서 ACK를 보내지만, 서버에서 클라이언트로 보내는 데이터 전송이 끝나면 전송의 종료에 대한 FIN을 보내게된다.
[Step4]에서 서버로부터 ACK를 받은후 바로 Closed가 아닌 Time-Wait하는 이유가 무엇일까?
1. 지연패킷 발생
지연으로 인해 FIN보다 늦게 도착하는 데이터가 있을수 있기 때문에 유실을 방지하고자 TIME-WAIT를 둔다.
지연패킷을 예상못하고 또 다른 연결을 진행했다면 해당 패킷(정말 우연으로 SEQ가 맞다면)으로 에러가 생길수 있다.
2. 원격 종단의 연결 확인 불가
만약 마지막 ACK 유실시(지연 등) 상대방은 LAST_ACK 상태로 연결이 지속되게 된다.
짧은 Time Out으로 새로운 연결을 위해 SYN 패킷 전달시 LAST_ACK 상태의 Passive Close는 RST 를 리턴한다. (RST는 아래 참조)
새로운 연결은 오류를 내며 실패한다.
따라서 반드시
TIME_WAIT
이 일정 시간 남아 패킷의 오작동을 막아야 한다. RFC 793 에는TIME_WAIT
을 2 MSL로 규정했다. 여기서 MSL은 maximum segment lifetime의 약자로 IP datagram이 네트워크에 존재할 수 있는 시간이다. TCP를 구현할 때 반드시 MSL값을 정해줘야하는데 RFC1122에 나온 추천은 2분이다. 그렇지만 Berkeley-derived implementation에서는 30초라서 보통 이 2MSL은 1분에서 4분정도 된다.
TCP 헤더에는 커넥션의 상태를 나타내는 필드가 있다. 9비트로 구성되어 있고 각각의 비트는 의미하는 바가 다르다.(ㅜㄴ)
1번째 비트
NS
CWR, ECE 필드가 실수나 악의적으로 은폐되는 경우를 막기위한 플래그
2번째 비트
CWR
Congestion Window Reduced
ECN-Echo에 따라, 혼잡 윈도우가 줄어든 것을 알리는 플래그
3번째 비트
ECE
ECN-Echo
혼잡이 발생한 것을 통신 상대에게 알리는 플래그
4번째 비트
URG
Urgent Pointer field significant
긴급을 나타내는 플래그
5번째 비트
ACK
Acknowledgment field significant
확인 응답을 나타내는 플래그
6번째 비트
PSH
Push Function
빠르게 애플리케이션에 데이터를 전달하는 플래그
7번째 비트
RST
Reset the connection
커넥션을 강제로 끊는 플래그
8번째 비트
SYN
Synchronize sequence numbers
커넥션을 여는 플래그
9번째 비트
FIN
No more data from sender
커넥션을 닫는 플래그
이 컨트롤 비트를 사용해 해당 패킷이 ACK, SYN, FIN 인지 확인 할 수 있다.
만약 TCP 커넥션을 4-way Handshake를 할 여유 없이 빨리 종료해야 하는 경우 RST 플래그를 1로 설정하면 된다. RST 플래그가 사용되는 경우는 아래와 같다.
존재하지 않는 TCP 연결에 대해 비SYN 세그먼트가 수신된 경우
열린 커넥션에서 일부 TCP 구현은 잘못된 헤더가 있는 세그먼트가 수신된 경우
일부 구현에서 기존 TCP 연결을 종료해야 하는 경우
원격 호스트에 연결할 수 없고 응답이 중지된 경우
이렇게 갑작스럽게 연결이 해제된 것을 Abrupt connection release 라고 부르고, 양쪽 커넥션이 서로 커넥션을 닫을 때까지 연결되어 있는 정상적인 종료를 Graceful connection release이라고 부른다.
클라이언트-서버가 연결이 되었고, 데이터를 주고받는 상황에서 클라이언트는 언제까지 데이터를 수신해야할까요?
계속 소켓(TCP연결)을 열어놓는다면? -> 블로킹상태로 에러가 나게될것입니다.
임의의 시점에 소켓을 닫아버린다면? -> 유실된 데이터로 에러가 발생할것입니다.
이러한 상황을 방지하기 위한 과정인 Half-Close 입니다.
그림과 같이 두 호스트가 연결되고, 데이터의 교환이 가능한 상태를 스트림이 형성된 상태라고 합니다.
스트림은 단방향으로만 형성되기에 데이터를 주고받기 위해서는 두개의 스트림이 필요합니다. 따라서, 두개의 호스트가 연결되면 두개의 스트림이 형성됩니다.
즉, Half-Close는 데이터의 마지막 송신시점에 출력 스트림을 끊어 데이터의 송신이 끝남을 알리는 방법을 의미합니다.
굳이Half-Close를 써야하나요?
무조건적인 방법은 아니지만, 안전한 종료를 위해 필요하다
마지막 송신에 마지막을 의미하는 특정 데이터를 보낼수도 있지만, 스트림을 통해 데이터를 주고받는 과정에서에 바이너리 데이터에 시그널 데이터가 포함되어 문제가 발생할수 있기때문에 Half-Close가 권장된다.