전송 계층(Transport Layer)은 OSI 7계층 모델에서 4번째 계층으로, 애플리케이션 간의 논리적 통신을 제공한다. 상위 계층(응용 계층)이 데이터 전달의 신뢰성이나 효율성을 고려하지 않도록 하며, 데이터를 세그먼트(또는 데이터그램) 단위로 관리한다. 전송 계층은 TCP/IP 모델과 OSI 모델 모두에 포함되며, 대표적인 프로토콜로 TCP와 UDP가 있다.
TCP (Transmission Control Protocol):
UDP (User Datagram Protocol):
TCP vs UDP:
소켓은 네트워크 통신의 엔드포인트로, IP 주소와 포트 번호를 결합하여 애플리케이션 간 데이터 교환을 가능하게 한다. 데이터 엔지니어링에서는 소켓을 통해 데이터 스트리밍, 데이터베이스 연결, 분산 시스템 간 통신을 구현한다.
TCP 헤더에는 6비트 제어 플래그(URG, ACK, PSH, RST, SYN, FIN)가 포함되어 통신의 상태와 동작을 제어한다.
3-way 핸드셰이킹은 TCP 연결을 설정하는 과정으로, 클라이언트와 서버가 신뢰성 있는 양방향 통신을 준비한다. 이는 PAR(Positive Acknowledgment with Retransmission) 메커니즘을 통해 신뢰성을 보장한다.
SYN (클라이언트 → 서버):
SYN
플래그를 설정하고 초기 시퀀스 번호(ISN, 예: seq=x
)를 랜덤으로 설정하여 서버에 전송한다.SYN-ACK (서버 → 클라이언트):
SYN
을 수신하고, SYN
과 ACK
플래그를 설정한 세그먼트를 전송한다.ACK
번호는 클라이언트의 seq=x
에 1을 더한 값(ack=x+1
)이고, 서버의 ISN(seq=y
)를 포함한다.ACK (클라이언트 → 서버):
SYN-ACK
를 수신하고, ACK
플래그를 설정한 세그먼트를 전송한다(ack=y+1
).3-way 핸드셰이킹은 데이터베이스 연결, ETL 파이프라인, 클라우드 스토리지와의 데이터 전송에서 안정적인 연결을 보장한다.
예를 들어, Snowflake나 Redshift에 쿼리를 전송하기 전에 이 과정이 수행된다.
4-way 핸드셰이킹은 TCP 연결을 종료하는 과정으로, Half-Close 기법을 사용하여 안전하게 연결을 닫는다.
FIN(+ACK) (클라이언트 → 서버):
FIN
플래그를 전송한다. ACK
번호를 포함하여 이전 데이터 수신을 확인한다.ACK (서버 → 클라이언트):
FIN
을 수신하고 ACK
를 전송한다(ack=클라이언트 seq+1
).FIN (서버 → 클라이언트):
FIN
플래그를 전송한다.ACK (클라이언트 → 서버):
FIN
을 수신하고 ACK
를 전송한다.FIN
을 보내면 일방향 연결만 종료되고, 서버는 남은 데이터를 전송할 수 있다. 이는 데이터 무결성을 보장한다.ACK
를 보낸 후 지연된 패킷(예: 라우팅 지연, 재전송 패킷)이 도착할 가능성에 대비해 일정 시간 세션을 유지한다. 이는 데드락을 방지한다.FIN
을 수신한 후에도 전송할 데이터가 남아 있을 수 있기 때문이다. 서버는 ACK
로 응답한 뒤 데이터를 모두 전송하고 FIN
을 보내야 한다.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 핸드셰이킹을 자동으로 수행하며, 간단한 메시지 교환을 구현한다.
A. 클라이언트가 데이터 전송을 완료해 FIN
을 보내더라도, 서버는 남은 데이터를 전송해야 할 수 있다. 따라서 서버는 ACK
로 응답한 뒤 데이터를 모두 전송하고 FIN
을 보내기 때문에 4단계가 필요하다.
A. 클라이언트는 TIME_WAIT 상태에서 지연된 패킷을 기다린다(기본 240초). 이를 통해 라우팅 지연이나 재전송 패킷이 오인되는 문제를 방지한다.
A. 포트 번호는 유한 범위 내에서 재사용되므로, 이전 연결의 패킷과 현재 연결의 패킷이 혼동될 가능성이 있다. 랜덤 ISN은 이를 방지하여 연결의 고유성을 보장한다.
TCP의 3-way 핸드셰이킹과 4-way 핸드셰이킹은 신뢰성 있는 데이터 전송의 핵심이다. 소켓, 플래그, ISN, TIME_WAIT 등의 개념은 데이터 엔지니어링에서 안정적인 데이터 파이프라인, 데이터베이스 연결, 분산 시스템을 설계하는 데 필수적이다. 이러한 메커니즘을 이해하면 데이터 무결성과 안정성을 보장하는 시스템을 구축할 수 있다.