TCP·UDP 기초: Handshake·Socket State·Routing·Subnet을 한 흐름으로 이해하기

반응형

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 동작을 먼저 확인한다.

참고 자료

반응형
KEEP READING
카테고리 전체 보기 →

댓글