본문 바로가기
카테고리 없음

TCP 연결 해제 과정 (4-Way Handshake) 에 대한 이해

by silvertogold100 2025. 9. 7.
반응형

TCP 연결 해제 과정 (4-Way Handshake)

TCP(Transmission Control Protocol)는 신뢰성 있는 연결 지향적 프로토콜로, 연결을 맺을 때뿐만 아니라 연결을 해제할 때도 정확한 절차를 따릅니다. TCP 연결 해제는 4-Way Handshake라는 과정을 통해 이루어지며, 양방향 연결을 안전하게 종료합니다.

TCP 연결의 양방향성

TCP 연결을 이해하기 위해서는 먼저 연결의 양방향성을 알아야 합니다:

  • TCP 연결은 전이중(Full-Duplex) 통신입니다
  • 클라이언트 → 서버 방향의 연결
  • 서버 → 클라이언트 방향의 연결
  • 두 방향이 독립적으로 종료될 수 있습니다

4-Way Handshake 과정

1단계: 클라이언트의 연결 종료 요청 (FIN)

클라이언트 → 서버: FIN 세그먼트 전송
  • FIN 플래그가 설정된 세그먼트를 전송
  • 클라이언트가 "더 이상 보낼 데이터가 없음"을 알림
  • 클라이언트는 FIN_WAIT_1 상태로 전환
  • 하지만 서버로부터 데이터는 여전히 받을 수 있습니다

2단계: 서버의 FIN 확인 응답 (ACK)

서버 → 클라이언트: ACK 세그먼트 전송
  • 서버가 클라이언트의 FIN을 확인했다는 ACK 전송
  • ACK 번호는 받은 FIN의 시퀀스 번호 + 1
  • 서버는 CLOSE_WAIT 상태로 전환
  • 클라이언트는 FIN_WAIT_2 상태로 전환
  • 서버는 아직 클라이언트로 데이터를 보낼 수 있습니다

3단계: 서버의 연결 종료 요청 (FIN)

서버 → 클라이언트: FIN 세그먼트 전송
  • 서버도 "더 이상 보낼 데이터가 없음"을 알리는 FIN 전송
  • 서버는 LAST_ACK 상태로 전환
  • 이제 양방향 모두 종료 요청이 완료됨

4단계: 클라이언트의 최종 확인 (ACK)

클라이언트 → 서버: ACK 세그먼트 전송
  • 클라이언트가 서버의 FIN에 대한 ACK 전송
  • 클라이언트는 TIME_WAIT 상태로 전환
  • 서버는 ACK를 받고 CLOSED 상태로 전환

TCP 상태 변화 다이어그램

클라이언트                           서버
ESTABLISHED ──┐                 ┌── ESTABLISHED
              │                 │
              │ ①FIN            │
              ├─────────────────→│
FIN_WAIT_1 ───┤                 ├─── CLOSE_WAIT
              │                 │
              │ ②ACK            │
              │←─────────────────┤
FIN_WAIT_2 ───┤                 │
              │                 │
              │ ③FIN            │
              │←─────────────────┤
TIME_WAIT ────┤                 ├─── LAST_ACK
              │                 │
              │ ④ACK            │
              ├─────────────────→│
              │                 │
   CLOSED ────┘                 └─── CLOSED

주요 TCP 상태 설명

FIN_WAIT_1

  • 클라이언트가 FIN을 보내고 ACK를 기다리는 상태
  • 능동적으로 연결을 종료하려는 측의 첫 번째 상태

FIN_WAIT_2

  • 서버로부터 ACK를 받았지만, 서버의 FIN을 기다리는 상태
  • 클라이언트 → 서버 방향은 종료되었지만, 서버 → 클라이언트는 아직 활성

CLOSE_WAIT

  • 클라이언트의 FIN을 받고 ACK를 보낸 후의 서버 상태
  • 애플리케이션이 종료 준비를 마치고 FIN을 보낼 때까지 대기

LAST_ACK

  • 서버가 FIN을 보내고 클라이언트의 ACK를 기다리는 상태

TIME_WAIT

  • 가장 중요한 상태 중 하나
  • 2MSL(Maximum Segment Lifetime) 동안 대기
  • 보통 30초~2분 정도

TIME_WAIT 상태의 중요성

왜 TIME_WAIT이 필요한가?

  1. 지연된 패킷 처리
    • 네트워크에서 지연되어 도착하는 패킷들을 기다림
    • 새로운 연결과 충돌하지 않도록 방지
  2. 마지막 ACK 재전송
    • 서버가 마지막 ACK를 받지 못한 경우를 대비
    • 서버가 FIN을 재전송하면 ACK로 응답할 수 있어야 함
  3. 포트 재사용 방지
    • 같은 포트로 새로운 연결이 즉시 생성되는 것을 방지
    • 이전 연결의 잔여 패킷과 새 연결의 패킷이 섞이지 않도록 함

TIME_WAIT과 성능

TIME_WAIT 상태는 시스템 리소스를 소모하므로, 고성능 서버에서는 다음과 같은 최적화 기법을 사용합니다:

  • SO_REUSEADDR 소켓 옵션 사용
  • Connection Pooling 기법
  • Keep-Alive 연결 재사용

비정상적인 연결 종료

RST(Reset) 세그먼트

4-Way Handshake 대신 RST 플래그를 사용하여 강제로 연결을 종료하는 경우:

  • 애플리케이션이 close() 대신 abort() 호출
  • 소켓 버퍼에 읽지 않은 데이터가 남아있을 때 종료
  • 예상치 못한 세그먼트를 받았을 때

Half-Close 상태

TCP는 한 방향만 종료하는 Half-Close를 지원합니다:

// 클라이언트에서 쓰기만 종료
shutdown(sockfd, SHUT_WR);  // FIN 전송
// 읽기는 여전히 가능

실제 코드에서의 연결 종료

클라이언트 측

// 정상적인 종료
close(sockfd);  // FIN 전송 후 4-Way Handshake 수행

// 강제 종료
struct linger ling;
ling.l_onoff = 1;
ling.l_linger = 0;
setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
close(sockfd);  // RST 전송

서버 측

// 클라이언트의 연결 종료 감지
while ((n = read(connfd, buffer, sizeof(buffer))) > 0) {
    // 데이터 처리
}
if (n == 0) {
    // 클라이언트가 FIN 전송 (정상 종료)
    close(connfd);
} else {
    // 에러 발생
    perror("read error");
}

성능 및 최적화 고려사항

TIME_WAIT 소켓 관리

# TIME_WAIT 상태의 소켓 확인
netstat -an | grep TIME_WAIT | wc -l

# 시스템 전체 TIME_WAIT 소켓 제한
echo 'net.ipv4.tcp_max_tw_buckets = 65536' >> /etc/sysctl.conf

서버 사이드 최적화

  • Connection Pooling: 연결을 재사용하여 4-Way Handshake 횟수 감소
  • Keep-Alive: 장시간 연결 유지로 연결 생성/해제 비용 절약
  • 비동기 I/O: 블로킹 없이 다수의 연결을 효율적으로 관리

결론

TCP 4-Way Handshake는 신뢰성 있는 연결 종료를 보장하는 중요한 메커니즘입니다. 각 단계의 의미와 상태 변화를 정확히 이해하면:

  1. 네트워크 문제 디버깅이 쉬워집니다
  2. 성능 최적화 전략을 세울 수 있습니다
  3. 안정적인 네트워크 애플리케이션을 개발할 수 있습니다

특히 TIME_WAIT 상태의 중요성을 이해하고, 적절한 최적화 기법을 적용하는 것이 고성능 네트워크 프로그래밍의 핵심입니다.

반응형