테마
L4 TCP와 UDP
전송 계층 개요
L4(전송 계층)는 호스트 간 통신 위에서 애플리케이션 엔드포인트를 구분합니다. IP 주소가 호스트를 찾는다면, 포트 번호는 그 호스트 안에서 어떤 서비스나 소켓 엔드포인트로 전달할지 결정합니다.
소켓(Socket)
소켓은 운영체제가 제공하는 통신 엔드포인트 인터페이스입니다. 유닉스 계열에서는 파일 디스크립터처럼 다루지만, 더 정확히는 커널의 네트워크 기능에 접근하는 OS 리소스라고 보는 편이 맞습니다.
- 소켓에 Write = 네트워크로 Send (송신)
- 소켓에서 Read = 네트워크로부터 Receive (수신)
TCP/IP는 운영체제 커널에 구현되어 있습니다. 유저 모드 애플리케이션은 소켓이라는 인터페이스를 통해 커널의 네트워크 기능을 사용합니다.
TCP vs UDP
TCP(Transmission Control Protocol)
연결 지향적이고 신뢰성 있는 전송 프로토콜입니다.
- 연결(Connection) 관리: 3-way Handshake로 연결, 4-way Handshake로 종료
- 순서 보장: 시퀀스 번호로 데이터 순서 관리
- 오류 복구: 유실 시 재전송
- 흐름 제어: 수신측 버퍼 상태에 따라 전송 속도 조절
- 혼잡 제어: 네트워크 상태에 따라 전송량 조절
UDP(User Datagram Protocol)
비연결형이고 구조가 단순한 전송 프로토콜입니다.
- 연결 절차 없음: 그냥 보냄
- 순서 보장 없음: 도착 순서 무관
- 오류 복구 없음: 유실되면 그만
- 빠른 전송이 장점
TCP 연결 관리
3-way Handshake (연결 수립)
연결 과정에서 교환되는 핵심 정보:
- 시퀀스 번호: 양 끝점이 각각 관리하는 32비트 번호 공간의 시작점(ISN)
- MSS(Maximum Segment Size): 보통 1,460 바이트
4-way Handshake (연결 종료)
연결 종료는 어느 쪽이든 시작할 수 있습니다. 다만 누가 먼저 FIN을 보내느냐에 따라 Active Close 측에 TIME_WAIT가 남기 때문에, 운영상 어느 쪽이 종료를 주도할지 설계 관점에서 생각해야 합니다.
서버 개발 시 실무 포인트:
- 프로토콜 차원에서 서버가 먼저 FIN을 보내는 것이 금지되는 것은 아닙니다
- 다만 대량 연결 서비스에서는 서버가 Active Close를 자주 수행하면
TIME_WAIT가 서버 쪽에 누적될 수 있습니다 RST는 비정상 종료나 즉시 중단이 필요할 때 쓰는 신호이지, 일반적인 종료 절차의 대체 수단은 아닙니다
TCP 상태 전이
이 상태 전이의 적정성을 검사하는 것이 Stateful Inspection이며, 방화벽에서 중요한 역할을 합니다.
Zero Window 문제
발생 원리
TCP 흐름 제어에서 자주 마주치는 상황입니다. 수신측 버퍼에 여유 공간이 없어져 상대에게 더 이상 보내지 말라고 광고하는 상태입니다.
원인과 해결
Zero Window가 발생했다고 해서 항상 애플리케이션 버그라고 단정할 수는 없습니다. 흔한 원인은 다음과 같습니다.
- 수신 애플리케이션이 데이터를 충분히 빨리 소비하지 못함
- 단일 스레드 처리 구조 때문에 읽기와 처리가 서로 막힘
- CPU, 메모리, 디스크 I/O 같은 리소스 병목으로 소비 속도가 느려짐
대표적인 완화 방법은 수신과 처리를 분리하고, 중간에 **큐(Queue)**를 두어 커널 버퍼를 빠르게 비우는 것입니다. 필요하면 버퍼 크기, 워커 수, 백프레셔 정책도 함께 점검합니다.
Zero Window는 "상대가 데이터를 안 보낸다"가 아니라 "내가 더 받을 준비가 안 됐다"는 신호에 가깝습니다. 그래서 서버 개발자가 송신 측만 볼 것이 아니라 수신 측 소비 속도와 버퍼 상태도 함께 확인해야 합니다.
AWS 환경에서의 TCP
AWS 내부(East-West 트래픽)는 일반적인 인터넷 구간보다 지연과 유실이 상대적으로 적은 편이지만, 그렇다고 0이라고 가정하면 안 됩니다. 실제 장애 분석에서는 애플리케이션 병목, 보안 그룹/NACL, DNS, 엔드포인트 설정, 리소스 포화와 함께 네트워크 상태를 종합적으로 봐야 합니다.