[CS] TCP의 3-Way Handshake와 4-Way Handshake

Hyunjun Kim·2025년 7월 20일
0

Computer_Science

목록 보기
16/19

1. 전송 계층과 TCP/UDP의 개요

전송 계층(Transport Layer)은 OSI 7계층 모델에서 4번째 계층으로, 애플리케이션 간의 논리적 통신을 제공한다. 상위 계층(응용 계층)이 데이터 전달의 신뢰성이나 효율성을 고려하지 않도록 하며, 데이터를 세그먼트(또는 데이터그램) 단위로 관리한다. 전송 계층은 TCP/IP 모델과 OSI 모델 모두에 포함되며, 대표적인 프로토콜로 TCP와 UDP가 있다.

1.1. 전송 계층 vs 네트워크 계층

  • 전송 계층: 애플리케이션 프로세스 간의 논리적 통신을 담당한다. 데이터의 신뢰성, 순서, 흐름 제어를 보장한다.
  • 네트워크 계층: 호스트 간의 논리적 통신을 담당한다. IP를 통해 데이터 전달 경로를 설정한다.

1.2. TCP와 UDP의 특징

  • TCP (Transmission Control Protocol):

    • 연결 지향 프로토콜로, 신뢰성 있는 데이터 전송을 보장한다.
    • 3-way 핸드셰이킹으로 연결을 설정하고, 4-way 핸드셰이킹으로 연결을 종료한다.
    • 흐름 제어(Sliding Window), 혼잡 제어(TCP Tahoe, Reno 등), 오류 검출 및 재전송(PAR: Positive Acknowledgment with Retransmission)을 수행한다.
    • 전이중(Full-Duplex), 점대점(Point-to-Point) 통신을 지원한다.
    • 신뢰성이 높지만 속도가 느리다.
    • 데이터 분석에서 대량 데이터 전송(예: ETL 파이프라인, 데이터베이스 쿼리)에 적합하다.
  • UDP (User Datagram Protocol):

    • 비연결형 프로토콜로, 데이터그램 단위로 데이터를 처리한다.
    • 연결 설정/종료 과정이 없으며, 흐름 제어나 혼잡 제어를 수행하지 않는다.
    • Checksum을 통한 최소한의 오류 검출만 제공한다.
    • 속도가 빠르고 네트워크 부하가 적지만, 신뢰성이 낮다.
    • 실시간 스트리밍(예: 비디오 스트리밍, VoIP)에 적합하다.
  • TCP vs UDP:

    • TCP와 UDP는 별도의 포트 주소 공간을 관리하므로 동일한 포트 번호를 사용해도 충돌하지 않는다.
    • 동적 포트(49,152~65,535)는 클라이언트가 여러 커넥션을 동시에 열 때 사용된다.


2. 소켓: 네트워크 통신의 인터페이스

소켓은 네트워크 통신의 엔드포인트로, IP 주소와 포트 번호를 결합하여 애플리케이션 간 데이터 교환을 가능하게 한다. 데이터 엔지니어링에서는 소켓을 통해 데이터 스트리밍, 데이터베이스 연결, 분산 시스템 간 통신을 구현한다.

2.1. 소켓의 유형

  • TCP 소켓: 신뢰성 있는 연결 지향 통신. 데이터 무결성이 중요한 경우(예: 데이터 웨어하우스 연결)에 사용된다.
  • UDP 소켓: 비연결형 통신. 속도가 중요한 실시간 애플리케이션에 적합하다.
  • 유닉스 소켓: 동일 호스트 내 프로세스 간 통신에 사용된다.

2.2. 소켓의 활용 (데이터 엔지니어링)

  • 실시간 데이터 파이프라인: Apache Kafka, Spark Streaming에서 TCP 소켓을 통해 데이터를 스트리밍한다.
  • 데이터베이스 통신: PostgreSQL, MySQL, Snowflake 등과의 연결에서 TCP 소켓이 사용된다.
  • 분산 시스템: Hadoop, Spark, Kubernetes에서 노드 간 통신에 소켓이 활용된다.


3. TCP 플래그: 통신 제어의 핵심

TCP 헤더에는 6비트 제어 플래그(URG, ACK, PSH, RST, SYN, FIN)가 포함되어 통신의 상태와 동작을 제어한다.

  • SYN (Synchronize): 연결 설정 요청. 초기 시퀀스 번호(ISN)를 설정하여 세션을 시작한다.
  • ACK (Acknowledgment): 데이터 수신 확인. 수신한 데이터의 다음 예상 바이트를 확인 번호로 전송한다.
  • FIN (Finish): 연결 종료 요청. 더 이상 전송할 데이터가 없음을 알린다.
  • RST (Reset): 비정상적인 연결 종료. 오류나 보안 문제 발생 시 사용된다.
  • PSH (Push): 데이터를 즉시 상위 계층으로 전달하도록 지시한다.
  • URG (Urgent): 긴급 데이터를 우선 처리하도록 지시한다.


4. [3-Way Handshake]: TCP 연결 설정

3-way 핸드셰이킹은 TCP 연결을 설정하는 과정으로, 클라이언트와 서버가 신뢰성 있는 양방향 통신을 준비한다. 이는 PAR(Positive Acknowledgment with Retransmission) 메커니즘을 통해 신뢰성을 보장한다.

4.1. 작동 방식

  1. SYN (클라이언트 → 서버):

    • 클라이언트는 SYN 플래그를 설정하고 초기 시퀀스 번호(ISN, 예: seq=x)를 랜덤으로 설정하여 서버에 전송한다.
    • 포트 상태: 클라이언트(SYN_SENT), 서버(LISTEN).
  2. SYN-ACK (서버 → 클라이언트):

    • 서버는 클라이언트의 SYN을 수신하고, SYNACK 플래그를 설정한 세그먼트를 전송한다.
    • ACK 번호는 클라이언트의 seq=x에 1을 더한 값(ack=x+1)이고, 서버의 ISN(seq=y)를 포함한다.
    • 포트 상태: 서버(SYN_RCV).
  3. ACK (클라이언트 → 서버):

    • 클라이언트는 서버의 SYN-ACK를 수신하고, ACK 플래그를 설정한 세그먼트를 전송한다(ack=y+1).
    • 이로써 양방향 연결이 설정된다(ESTABLISHED).
    • 데이터 전송은 이 단계에서 시작될 수 있다.

4.2. ISN(Initial Sequence Number)의 중요성

  • ISN은 0이 아닌 랜덤 값으로 설정된다. 이는 이전 연결의 패킷과 현재 연결의 패킷을 구분하기 위함이다.
  • 포트 번호는 유한 범위(0~65,535) 내에서 재사용되므로, 동일 포트 쌍에서 이전 연결의 패킷이 오인되지 않도록 ISN을 난수로 설정한다.

3-way 핸드셰이킹은 데이터베이스 연결, ETL 파이프라인, 클라우드 스토리지와의 데이터 전송에서 안정적인 연결을 보장한다.
예를 들어, Snowflake나 Redshift에 쿼리를 전송하기 전에 이 과정이 수행된다.



5. 4-Way Handshake: TCP 연결 종료

4-way 핸드셰이킹은 TCP 연결을 종료하는 과정으로, Half-Close 기법을 사용하여 안전하게 연결을 닫는다.

5.1. 작동 방식

  1. FIN(+ACK) (클라이언트 → 서버):

    • 클라이언트가 연결 종료를 요청하며 FIN 플래그를 전송한다. ACK 번호를 포함하여 이전 데이터 수신을 확인한다.
    • 포트 상태: 클라이언트(FIN_WAIT_1), 서버(CLOSE_WAIT).
  2. ACK (서버 → 클라이언트):

    • 서버는 클라이언트의 FIN을 수신하고 ACK를 전송한다(ack=클라이언트 seq+1).
    • 서버는 남은 데이터를 전송하며 CLOSE_WAIT 상태를 유지한다.
    • 클라이언트는 FIN_WAIT_2 상태로 전환한다.
  3. FIN (서버 → 클라이언트):

    • 서버가 모든 데이터 전송을 완료하면 FIN 플래그를 전송한다.
    • 포트 상태: 서버(LAST_ACK).
  4. ACK (클라이언트 → 서버):

    • 클라이언트는 서버의 FIN을 수신하고 ACK를 전송한다.
    • 클라이언트는 TIME_WAIT 상태로 전환하여 지연된 패킷을 기다린다(기본 240초).
    • 서버는 ACK 수신 후 CLOSED 상태로 전환한다.
    • TIME_WAIT 종료 후 클라이언트도 CLOSED 상태로 전환한다.

5.2. Half-Close와 TIME_WAIT의 역할

  • Half-Close: 클라이언트가 FIN을 보내면 일방향 연결만 종료되고, 서버는 남은 데이터를 전송할 수 있다. 이는 데이터 무결성을 보장한다.
  • TIME_WAIT: 클라이언트가 마지막 ACK를 보낸 후 지연된 패킷(예: 라우팅 지연, 재전송 패킷)이 도착할 가능성에 대비해 일정 시간 세션을 유지한다. 이는 데드락을 방지한다.

5.3. Abrupt 종료

  • RST 플래그: 비정상적인 상황(예: 잘못된 헤더, 리소스 부족, 비존재 연결로의 요청)에서 연결을 강제로 종료한다.
  • 데이터 엔지니어링에서는 RST로 인한 연결 실패를 모니터링하여 파이프라인 안정성을 점검한다.


6. 3-Way와 4-Way의 단계 차이 이유

  • 3-way 핸드셰이킹은 연결 설정에 3단계가 필요한 이유는 양방향 통신 파라미터(시퀀스 번호)를 설정하고 확인하기 위함이다.
  • 4-way 핸드셰이킹은 연결 종료에 4단계가 필요한 이유는 서버가 클라이언트의 FIN을 수신한 후에도 전송할 데이터가 남아 있을 수 있기 때문이다. 서버는 ACK로 응답한 뒤 데이터를 모두 전송하고 FIN을 보내야 한다.


7. 실제 예제: Python으로 TCP 소켓 구현

TCP 소켓을 활용한 간단한 클라이언트-서버 통신 예제를 제공한다. 이 코드는 데이터 엔지니어가 TCP 통신을 테스트하거나 프로토타입을 만들 때 유용하다.

서버 코드

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 12345))
server_socket.listen(1)

print("서버가 시작되었습니다. 클라이언트를 기다립니다...")
conn, addr = server_socket.accept()
print(f"연결된 클라이언트: {addr}")

data = conn.recv(1024).decode()
print(f"수신된 메시지: {data}")

conn.send("서버로부터의 응답".encode())
conn.close()
server_socket.close()

클라이언트 코드

import socket

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 12345))

client_socket.send("안녕하세요!".encode())

data = client_socket.recv(1024).decode()
print(f"서버 응답: {data}")

client_socket.close()

이 코드는 3-way 핸드셰이킹을 자동으로 수행하며, 간단한 메시지 교환을 구현한다.



8. TCP 관련 FAQ

Q1. 3-way와 4-way 핸드셰이킹의 단계가 다른 이유는?

A. 클라이언트가 데이터 전송을 완료해 FIN을 보내더라도, 서버는 남은 데이터를 전송해야 할 수 있다. 따라서 서버는 ACK로 응답한 뒤 데이터를 모두 전송하고 FIN을 보내기 때문에 4단계가 필요하다.

Q2. FIN 패킷보다 늦게 도착하는 패킷은 어떻게 처리되나?

A. 클라이언트는 TIME_WAIT 상태에서 지연된 패킷을 기다린다(기본 240초). 이를 통해 라우팅 지연이나 재전송 패킷이 오인되는 문제를 방지한다.

Q3. ISN을 랜덤으로 설정하는 이유는?

A. 포트 번호는 유한 범위 내에서 재사용되므로, 이전 연결의 패킷과 현재 연결의 패킷이 혼동될 가능성이 있다. 랜덤 ISN은 이를 방지하여 연결의 고유성을 보장한다.



9. 결론

TCP의 3-way 핸드셰이킹과 4-way 핸드셰이킹은 신뢰성 있는 데이터 전송의 핵심이다. 소켓, 플래그, ISN, TIME_WAIT 등의 개념은 데이터 엔지니어링에서 안정적인 데이터 파이프라인, 데이터베이스 연결, 분산 시스템을 설계하는 데 필수적이다. 이러한 메커니즘을 이해하면 데이터 무결성과 안정성을 보장하는 시스템을 구축할 수 있다.

profile
Data Analytics Engineer 가 되

0개의 댓글