network 통신을 읽으려면 protocol 이름을 따로 외우기보다 packet이 주소를 고르고, route를 따라가고, transport endpoint에 도착해, connection state를 바꾸는 흐름으로 연결하는 편이 좋다. 이 글은 TCP·UDP, TCP state, routing, IPv4 subnet에서 자주 생기는 오해를 함께 정리한다.
TCP와 UDP는 ‘느림 대 빠름’이 아니다
| 구분 | TCP | UDP |
|---|---|---|
| 전달 형태 | ordered byte stream | independent datagram |
| connection state | endpoint가 연결 state를 유지 | protocol 자체의 connection handshake 없음 |
| 기본 제공 | sequence, acknowledgment, retransmission, flow·congestion control | port와 length·checksum을 가진 최소한의 datagram delivery |
| message boundary | 보존하지 않음 | datagram boundary 보존 |
| application 책임 | framing, timeout, retry 정책 | 필요 시 ordering·retry·congestion control 등을 상위 protocol에서 구현 |
TCP가 reliability mechanism을 제공해도 network failure나 application failure가 사라지는 것은 아니다. write() 성공이 remote application의 처리 완료를 보장하지도 않는다. UDP도 단순히 ‘손실되지만 빠른 protocol’은 아니다. DNS처럼 작은 request-response에 쓰이고, QUIC처럼 UDP 위에서 reliability·congestion control·TLS를 제공하는 transport도 있다.
protocol 선택은 latency 하나가 아니라 message boundary, head-of-line behavior, congestion control, NAT·firewall, implementation complexity를 함께 본다.
TCP Three-way Handshake가 확인하는 것
일반적인 active open 흐름은 다음과 같다.
initiator listener
| -------- SYN, seq=x ----------> |
| <--- SYN+ACK, seq=y, ack=x+1 -- |
| -------- ACK, ack=y+1 --------> |
두 endpoint는 initial sequence number를 동기화하고, 오래된 duplicate segment로 잘못된 connection이 만들어질 가능성을 줄인다. 이 절차가 router에 고정된 packet path를 예약하거나 application-level reliability를 보증하는 것은 아니다. 이후 packet은 routing 변화에 따라 다른 path를 지날 수도 있다.
‘client가 SYN, server가 SYN-ACK’은 일반적인 설명이지만 TCP state machine은 peer 관점이다. simultaneous open처럼 양쪽이 SYN을 보낼 수도 있다.
Connection 종료가 항상 네 packet인 것은 아니다
TCP는 full-duplex라 각 방향을 독립적으로 닫을 수 있다. 한쪽이 더 보낼 data가 없으면 FIN을 보내고, peer는 이를 ACK한 뒤 자신의 전송도 끝났을 때 FIN을 보낸다. 이 흐름이 흔히 ‘four-way handshake’로 그려진다.
active closer passive closer
| --------------- FIN ----------> |
| <-------------- ACK ----------- |
| <-------------- FIN ----------- |
| --------------- ACK ----------> |
하지만 ACK와 FIN이 한 segment에 합쳐지거나 양쪽이 동시에 close할 수 있어 항상 정확히 네 packet이라고 단정할 수 없다. abortive close에서는 RST가 관여할 수 있다.
Linux에서 보는 TCP Socket State
RFC 9293의 state는 ‘client 상태’와 ‘server 상태’가 아니라 local endpoint가 현재 무엇을 기다리는지 나타낸다.
| State | local endpoint의 의미 |
|---|---|
LISTEN |
remote connection request를 기다림 |
SYN-SENT |
connection request를 보낸 뒤 matching response를 기다림 |
SYN-RECEIVED |
SYN을 받고 SYN도 보낸 뒤 확인 ACK를 기다림 |
ESTABLISHED |
data transfer가 가능한 open connection |
FIN-WAIT-1 |
local close 후 FIN의 ACK 또는 peer FIN을 기다림 |
FIN-WAIT-2 |
local FIN은 ACK됐고 peer FIN을 기다림 |
CLOSE-WAIT |
peer FIN을 받아 local application이 close하기를 기다림 |
LAST-ACK |
passive close 뒤 local FIN의 ACK을 기다림 |
CLOSING |
양쪽 FIN이 교차했고 local FIN의 ACK을 기다림 |
TIME-WAIT |
active close 뒤 delayed segment와 final ACK 재전송 가능성에 대비 |
ss -lntp
ss -tan state syn-sent
ss -tan state close-wait
ss -tan state time-wait
CLOSE-WAIT가 계속 쌓이면 kernel이 임의로 닫지 않는 문제가 아니라 local application이 close를 완료하지 않는 path를 의심한다. TIME-WAIT가 많다는 사실만으로 장애는 아니다. connection churn, port range, tuple reuse, latency·error를 함께 본다.
Routing은 ‘최적 경로’라는 한 문장보다 구체적이다
host는 destination address와 policy rule을 바탕으로 routing table을 조회해 next hop, interface, source address 등을 선택한다. 일반적으로 longest-prefix match가 핵심이지만 metric과 policy routing, multiple table, ECMP도 결과에 영향을 준다.
ip rule show
ip route show
ip route get 203.0.113.10
static route는 관리자가 명시한 경로이고, dynamic routing protocol은 topology 정보를 교환해 route를 계산한다.
- OSPF는 한 autonomous system 내부에서 link-state 정보를 사용한다.
- BGP는 autonomous system 사이와 내부에서 policy를 반영해 reachability를 교환한다.
- RIP은 hop count 기반의 오래된 distance-vector protocol로 규모와 convergence에 제약이 있다.
BGP를 단순히 ‘인터넷의 최단 경로 protocol’이라고 보면 안 된다. AS path 외에도 local policy와 여러 attribute가 route selection에 관여한다.
IPv4 CIDR과 Subnet 계산
192.168.1.10/24에서 /24는 앞 24bit가 network prefix라는 뜻이다. 이 주소가 속한 network는 192.168.1.0/24이고 전통적인 subnet의 broadcast address는 192.168.1.255다.
| Prefix | Address 수 | 전통적 subnet에서 host로 쓰는 수 |
|---|---|---|
/8 |
16,777,216 | 16,777,214 |
/16 |
65,536 | 65,534 |
/24 |
256 | 254 |
2^(32-prefix)-2는 모든 IPv4 prefix에 적용하는 절대 공식이 아니다. point-to-point /31은 RFC 3021 방식으로 두 주소를 endpoint에 사용할 수 있고 /32는 한 host route를 표현한다. cloud platform은 subnet마다 provider-reserved address를 더 둘 수 있으므로 실제 usable address는 해당 platform 문서를 확인한다. IPv6에는 IPv4식 broadcast가 없다.
Python의 ipaddress로 계산할 때도 object의 의미를 확인한다.
import ipaddress
network = ipaddress.ip_network("192.168.1.10/24", strict=False)
print(network.network_address) # 192.168.1.0
print(network.broadcast_address) # 192.168.1.255
print(network.num_addresses) # 256
print(sum(1 for _ in network.hosts())) # 254
큰 network에서 host 수만 필요하다면 전체 iterator를 순회하기보다 prefix와 환경의 reserved-address rule로 계산한다.
실제 장애에서 이 개념을 사용하는 순서는 Kubernetes network troubleshooting 흐름, route 선택의 상세는 라우팅 테이블과 packet 전달로 이어진다.
자주 묻는 질문
TCP는 packet 순서를 보장하나
application에는 ordered byte stream을 제공한다. 개별 IP packet이 network에서 순서대로 도착해야 한다는 뜻은 아니며 TCP가 sequence number와 buffering으로 순서를 복구한다. application message boundary는 따로 정의해야 한다.
UDP에는 checksum이 없나
UDP header에는 checksum field가 있다. IPv4 UDP에서는 0으로 전송해 미사용을 나타낼 수 있었지만 IPv6에서는 일반적으로 checksum이 필수다. checksum도 전달·순서·재전송을 제공하지는 않는다.
TIME-WAIT을 바로 없애면 성능이 좋아지나
TIME-WAIT은 delayed segment와 마지막 ACK 유실에 대응하는 protocol 역할이 있다. kernel tuning보다 connection pattern, port exhaustion evidence, keep-alive와 load balancer 동작을 먼저 확인한다.
참고 자료
'배움과 성장 > 네트워크·보안' 카테고리의 다른 글
| TCP 혼잡 제어 동작 순서: cwnd·slow start·fast recovery 이해하기 (10) | 2025.08.24 |
|---|---|
| Kubernetes 네트워크 트러블슈팅 순서: DNS·TCP·TLS·HTTP를 증거로 좁히기 (0) | 2025.03.25 |
| 실시간 통신 방식 비교: 폴링·SSE·WebSocket·모바일 푸시 선택 기준 (2) | 2024.12.05 |
| Linux 네트워크 트러블슈팅: DNS부터 TCP·TLS·HTTP까지 (1) | 2024.12.04 |
| CDN POP 선택 원리: DNS·Anycast·HTTP 리디렉션은 어떻게 다른가 (1) | 2024.12.04 |
댓글