TCP 연결은 어떻게 종료되는가: FIN·RST·TIME_WAIT 이해하기
TCP 연결은 어떻게 종료되는가: FIN·RST·TIME_WAIT 이해하기#
1장 연결이 만들어지는 것만큼 종료도 중요하다#
1.1 연결이 끝났는데 왜 소켓은 계속 남아 있을까#
주차관제 Server에 수십 대의 Controller가 TCP로 연결되어 있다고 가정해보겠습니다.
처음에는 정상적으로 동작합니다.
그런데 시간이 지나면서:
새로운 장비 연결 지연
접속 가능한 장비 수 감소
TCP Socket 수 증가
Server Memory 사용량 증가같은 현상이 나타납니다.
ss 명령으로 확인했더니 다음과 같은 상태가 많이 보입니다.
TIME-WAIT
CLOSE-WAIT
FIN-WAIT-1
FIN-WAIT-2이 상태들을 모르고 보면 모두:
연결이 제대로 안 끊긴 것 같다.
라고 생각하기 쉽습니다.
하지만 TCP는 연결을 만들 때뿐 아니라 연결을 종료할 때도 상태를 관리합니다.
어떤 상태는 정상이고, 어떤 상태가 지나치게 오래 쌓인다면 Application 문제의 강력한 단서가 될 수 있습니다.
1.2 TCP는 양방향 통신이다#
TCP Connection을 다음과 같이 생각해보겠습니다.
Client
⇄
ServerTCP는 Full Duplex 통신이므로:
Client → Server
Server → Client두 방향이 독립적으로 존재합니다.
따라서 한쪽이:
나는 이제 더 이상 데이터를 보내지 않겠다.
고 선언해도 상대방은 아직 데이터를 보낼 수 있습니다.
이 점을 이해해야 FIN의 의미를 정확하게 이해할 수 있습니다.
2장 FIN은 무엇을 의미하는가#
2.1 FIN은 Connection 전체를 즉시 없애는 신호가 아니다#
FIN은 TCP Header의 Flag 중 하나입니다.
FIN을 보낸다는 것은 기본적으로:
이 방향에서는 더 이상 보낼 데이터가 없다.
는 의미입니다.
예를 들어 Client가 FIN을 보냈다고 가정합니다.
Client Server
FIN
─────────────────────────────→이것은:
Client → Server
더 이상 데이터 전송하지 않음을 의미합니다.
하지만 반대 방향인:
Server → Client까지 즉시 종료됐다는 뜻은 아닙니다.
2.2 TCP의 Half-Close#
TCP에서는 한 방향만 먼저 종료될 수 있습니다.
이를 이해하기 쉽게 Half-Close라고 부릅니다.
예:
Client → Server
종료
Server → Client
아직 가능즉:
Client
FIN
──────→ Server
Client
←────── Server Data같은 상황도 가능합니다.
이 구조 때문에 TCP 정상 종료가 단순히:
FIN
→ 끝이 아니라 여러 단계로 진행됩니다.
3장 정상적인 TCP 종료 흐름#
3.1 첫 번째 FIN#
Client가 먼저 Connection 종료를 시작한다고 가정하겠습니다.
Client Server
FIN
─────────────────────────────→Client 입장에서는:
더 이상 보낼 데이터가 없음을 알립니다.
3.2 Server가 ACK한다#
Server는 FIN을 받으면 이를 확인합니다.
Client Server
FIN
─────────────────────────────→
ACK
←─────────────────────────────이 순간 Server는 Client가 보내는 방향이 종료됐다는 것을 압니다.
하지만 Server가 아직 보낼 데이터가 있다면 계속 보낼 수 있습니다.
3.3 Server도 자신의 FIN을 보낸다#
Server Application까지 데이터 처리를 마치고 자신도 더 이상 보낼 데이터가 없다면 FIN을 보냅니다.
Client Server
FIN
─────────────────────────────→
ACK
←─────────────────────────────
FIN
←─────────────────────────────3.4 마지막 ACK#
Client는 Server의 FIN을 확인합니다.
Client Server
FIN
─────────────────────────────→
ACK
←─────────────────────────────
FIN
←─────────────────────────────
ACK
─────────────────────────────→이를 흔히 4-Way Handshake라고 설명합니다.
다만 실제 Packet에서는 ACK와 FIN이 하나의 Segment에 함께 포함되는 경우도 있으므로 항상 정확히 네 개의 Packet으로만 보이는 것은 아닙니다.
4장 FIN과 ACK의 Sequence Number 관계#
4.1 FIN도 Sequence Number 공간을 하나 사용한다#
앞서 TCP SYN이 Sequence Number 공간에서 하나를 사용한다고 배웠습니다.
FIN도 마찬가지입니다.
예를 들어 Client가:
FIN
Seq = 5000을 보냈다면 Server의 ACK는:
Ack = 5001이 될 수 있습니다.
즉:
FIN Seq 5000
↓
ACK 5001입니다.
Packet Capture에서 정상 종료를 읽을 때 이 관계를 확인하면 도움이 됩니다.
5장 TCP 종료 상태를 이해하자#
TCP 종료 장애를 분석하려면 몇 가지 상태를 알아야 합니다.
대표적으로:
ESTABLISHED
FIN_WAIT_1
FIN_WAIT_2
CLOSE_WAIT
LAST_ACK
TIME_WAIT
CLOSED가 있습니다.
이 상태들은 모두 같은 문제가 아니라 TCP 종료 과정의 서로 다른 위치를 나타냅니다.
6장 FIN_WAIT_1과 FIN_WAIT_2#
6.1 FIN_WAIT_1#
먼저 FIN을 보낸 쪽은 일반적으로:
ESTABLISHED
↓
FIN 전송
↓
FIN_WAIT_1상태로 이동합니다.
이 상태에서는 자신이 보낸 FIN에 대한 ACK를 기다리고 있습니다.
6.2 FIN_WAIT_2#
상대방이 FIN을 ACK하면:
FIN_WAIT_1
↓
FIN에 대한 ACK 수신
↓
FIN_WAIT_2가 될 수 있습니다.
이제 자신은 데이터를 모두 보냈지만 상대방은 아직 자신의 FIN을 보내지 않은 상태입니다.
개념적으로:
나
더 이상 송신 안 함
상대
아직 송신 가능입니다.
7장 CLOSE_WAIT는 무엇인가#
7.1 상대방의 FIN을 받은 쪽에서 나타난다#
Server가 Client의 FIN을 받았다고 가정합니다.
Server TCP Stack은 FIN에 ACK를 보냅니다.
그리고 Server 쪽 Socket은:
ESTABLISHED
↓
상대 FIN 수신
↓
CLOSE_WAIT상태가 될 수 있습니다.
이 이름을 그대로 해석하면:
상대는 연결을 닫겠다고 했고, 이제 내 Application이 이 Socket을 닫기를 기다리는 상태
라고 이해할 수 있습니다.
7.2 CLOSE_WAIT는 TCP가 기다리는 문제가 아니라 Application이 닫기를 기다리는 상태다#
매우 중요합니다.
CLOSE_WAIT에서 TCP Stack은 이미 상대방의 FIN을 받았습니다.
이제 Application이:
close()같은 종료 처리를 해야 합니다.
Application이 Socket을 제대로 닫지 않으면 CLOSE_WAIT가 계속 남아 있을 수 있습니다.
따라서:
CLOSE_WAIT가 대량으로 오래 유지된다면 가장 먼저:
Application이 Socket을 제대로 close하는가?를 확인해야 합니다.
8장 LAST_ACK는 무엇인가#
CLOSE_WAIT 상태의 Application이 Socket을 닫으면 자신의 FIN을 보냅니다.
CLOSE_WAIT
↓
Application close()
↓
FIN 전송
↓
LAST_ACKLAST_ACK 상태에서는:
내가 보낸 마지막 FIN에 대한 ACK를 기다리고 있다.
라고 이해할 수 있습니다.
상대방의 ACK를 받으면 Connection 상태가 최종적으로 정리됩니다.
9장 TIME_WAIT는 무엇인가#
9.1 마지막 ACK를 보낸 쪽에서 주로 나타난다#
정상적인 종료에서 마지막 FIN을 받고 ACK를 보낸 쪽은 즉시 Connection 정보를 모두 없애지 않습니다.
대신 일정 시간:
TIME_WAIT상태를 유지합니다.
9.2 TIME_WAIT가 필요한 첫 번째 이유 — 마지막 ACK 유실#
다음 상황을 생각해보겠습니다.
Server
FIN
──────→ Client
Client
ACK
──────→ Server그런데 마지막 ACK가 Network에서 사라졌습니다.
Server는 자신의 FIN이 확인되지 않았다고 생각하고 FIN을 다시 보낼 수 있습니다.
Server
FIN 재전송
──────→ ClientClient가 TIME_WAIT 상태를 유지하고 있다면 이 FIN을 인식하고 마지막 ACK를 다시 보낼 수 있습니다.
9.3 TIME_WAIT가 필요한 두 번째 이유 — 오래된 Segment 제거#
Network에서 지연된 Segment가 한참 뒤에 도착할 가능성도 고려해야 합니다.
예를 들어 기존 Connection이 끝난 직후 동일한:
Source IP
Source Port
Destination IP
Destination Port조합을 새로운 Connection에서 바로 재사용한다고 생각해보겠습니다.
이전 Connection의 늦은 Segment가 새로운 Connection에 섞이면 문제가 될 수 있습니다.
TIME_WAIT은 이런 오래된 Segment가 Network에서 사라질 시간을 확보하는 역할도 합니다.
9.4 TIME_WAIT 자체는 오류가 아니다#
Server에서:
TIME-WAIT
TIME-WAIT
TIME-WAIT
TIME-WAIT가 많이 보이면 처음에는 장애처럼 느껴질 수 있습니다.
하지만 짧은 TCP Connection을 많이 만드는 시스템에서는 TIME_WAIT가 많이 생기는 것이 자연스러울 수도 있습니다.
중요한 것은 단순 개수가 아니라:
Connection 생성률
동시 Connection 수
Ephemeral Port 사용량
File Descriptor
Memory
Application 구조와 함께 보는 것입니다.
10장 TIME_WAIT와 Port 고갈#
10.1 Client가 매우 많은 Outbound Connection을 반복한다면#
예를 들어 Client가 Server에 연결할 때마다 새로운 Source Port를 사용한다고 하겠습니다.
192.168.10.20:50001
→ Server:443
192.168.10.20:50002
→ Server:443
192.168.10.20:50003
→ Server:443짧은 Connection을 매우 빠르게 만들고 닫으면 많은 Source Port가 TIME_WAIT와 함께 일정 시간 묶일 수 있습니다.
극단적인 경우 사용 가능한 Ephemeral Port 범위에 압박을 줄 수 있습니다.
10.2 Server Port 443 자체가 TIME_WAIT 때문에 사라지는 것은 아니다#
여기서 자주 생기는 오해가 있습니다.
Server가:
TCP 443
LISTEN하고 있다고 가정합니다.
개별 Connection은 다음과 같은 조합으로 구분됩니다.
Client IP
Client Port
Server IP
Server Port따라서 TIME_WAIT가 존재한다고 해서 Server의 TCP 443 Listening Socket 자체를 다른 Client가 사용할 수 없게 되는 것은 아닙니다.
Port 고갈 문제는 어느 Endpoint가 Active Close를 하고 어떤 주소·Port 조합을 대량으로 사용하는지를 함께 봐야 합니다.
11장 CLOSE_WAIT가 많을 때가 더 위험한 경우가 있다#
11.1 상대는 이미 연결을 끝냈다#
CLOSE_WAIT가 있다는 것은 상대방의 FIN이 이미 도착했다는 뜻입니다.
Remote
FIN
↓
Local TCP Stack
ACK
↓
CLOSE_WAIT이제 남은 것은 Local Application이 Socket을 닫는 것입니다.
11.2 Application이 close하지 않으면 Resource가 남는다#
Application Code가 잘못되어:
Connection 종료 감지
↓
예외 발생
↓
close() 실행 안 됨같은 상황이 반복되면 Socket이 계속 남을 수 있습니다.
결과적으로:
CLOSE_WAIT 증가
↓
File Descriptor 증가
↓
Memory 사용 증가
↓
새 Socket 생성 실패
↓
새로운 Client 연결 장애로 이어질 수 있습니다.
이것이 실제 Connection Leak에 가까운 상황입니다.
12장 Connection Leak은 무엇인가#
Connection Leak은 Application이 더 이상 필요하지 않은 Network Connection을 적절히 정리하지 않아 Resource가 계속 남는 문제를 말합니다.
대표적인 원인은:
예외 처리 누락
Socket close 누락
Thread 정리 실패
Connection Pool 반환 실패
Library 사용 오류
비정상적인 상태 관리등입니다.
12.1 TCP 상태만 보고 Leak이라고 단정하지 않는다#
다음 상태가 많다고 무조건 Leak은 아닙니다.
TIME_WAIT반면:
CLOSE_WAIT가 장시간 지속
+
File Descriptor 증가
+
Application Memory 증가같은 증거가 함께 있다면 Application Resource Leak을 더 강하게 의심할 수 있습니다.
13장 RST는 FIN과 무엇이 다른가#
13.1 FIN은 정상적인 종료 의사 표시다#
FIN:
"나는 이 방향의 전송을 정상적으로 마치겠다."라고 볼 수 있습니다.
13.2 RST는 즉각적인 Connection Reset이다#
RST는 Reset입니다.
개념적으로:
현재 Connection 상태를
정상 FIN 절차 없이
즉시 중단하는 데 사용됩니다.
Packet Capture에서는:
Flags [R]또는:
Flags [R.]같이 보일 수 있습니다.
14장 RST는 언제 발생할까#
RST는 다양한 상황에서 발생할 수 있습니다.
14.1 Listen하지 않는 Port에 연결#
Client:
Server:6000
SYNServer에 해당 Port를 Listen하는 Service가 없다면 운영체제가 RST를 보낼 수 있습니다.
SYN
──────→
RST
←──────14.2 Application이 Connection을 강제로 중단#
Application의 종료 방식이나 Socket Option에 따라 정상적인 FIN이 아니라 RST가 나타날 수도 있습니다.
14.3 존재하지 않는 Connection에 Segment가 도착#
TCP Stack이 현재 유효하지 않은 Connection에 대한 Segment를 받았을 때도 조건에 따라 RST가 발생할 수 있습니다.
14.4 중간 Network 장비가 Reset을 생성하는 경우#
일부 Firewall이나 Load Balancer 등이 정책에 따라 TCP RST를 생성하는 경우도 있습니다.
따라서:
RST 발견
=
Server Application이 보냈다라고 바로 판단하면 안 됩니다.
누가 RST를 보냈는지 확인하는 것이 중요합니다.
15장 갑작스러운 장비 전원 OFF는 항상 RST를 보내는가#
아닙니다.
예를 들어 Controller의 전원이 갑자기 꺼졌다고 생각해보겠습니다.
전원이 사라졌기 때문에 장비가:
RST 전송할 기회 자체가 없을 수 있습니다.
상대 Server는 당분간 Connection이 살아 있다고 생각할 수도 있습니다.
Server
ESTABLISHED
Controller
전원 OFF이런 상태는 Application Traffic이나 TCP Keepalive, 별도의 Timeout 등에 의해 나중에 감지될 수 있습니다.
따라서:
비정상 종료
=
항상 RST라고 이해하면 안 됩니다.
16장 kill -9를 하면 항상 RST가 발생하는가#
이 역시 단정하면 안 됩니다.
Process가 강제 종료되면 운영체제가 해당 Process의 Socket을 정리하게 되지만 실제 Wire상에서:
FIN
RST
아무 Packet 없음중 무엇이 나타날지는 Socket 상태와 운영체제 동작, 설정 등에 따라 달라질 수 있습니다.
따라서 실습에서:
kill -9를 하면 RST가 나온다.
를 정답처럼 외우는 것은 적절하지 않습니다.
실제 Packet Capture로 확인해야 합니다.
17장 정상적인 종료 Packet을 직접 읽어보자#
예를 들어 Client가 먼저 종료한다고 가정합니다.
10.0.0.10:45000
→
10.0.0.5:6000단순화한 Capture는 다음과 비슷할 수 있습니다.
10.0.0.10.45000 > 10.0.0.5.6000
Flags [F.]
seq 1000
ack 2000
10.0.0.5.6000 > 10.0.0.10.45000
Flags [.]
ack 1001
10.0.0.5.6000 > 10.0.0.10.45000
Flags [F.]
seq 2000
ack 1001
10.0.0.10.45000 > 10.0.0.5.6000
Flags [.]
ack 2001핵심만 보면:
FIN
↓
ACK
↓
FIN
↓
ACK입니다.
18장 실제로는 FIN과 ACK가 합쳐질 수도 있다#
항상 정확히 네 Packet으로 나타나는 것은 아닙니다.
상대방이 FIN을 받고 자신도 바로 종료할 준비가 되어 있다면:
FIN + ACK를 한 Segment에서 보낼 수도 있습니다.
예:
Client Server
FIN
─────────────────────────────→
FIN + ACK
←─────────────────────────────
ACK
─────────────────────────────→따라서 Packet 분석에서:
반드시 네 Packet이어야 정상이라고 판단해서는 안 됩니다.
19장 ss로 TCP 상태 확인하기#
Linux에서는 ss를 이용해 TCP Socket 상태를 확인할 수 있습니다.
예:
ss -tan특정 Port를 확인하려면:
ss -tan | grep ':6000'처럼 사용할 수 있습니다.
19.1 Process 정보까지 확인하기#
권한이 있다면:
ss -tanp를 사용해 Socket과 관련 Process를 함께 확인할 수 있습니다.
예:
ESTAB
10.0.0.5:6000
10.0.0.10:45000
CLOSE-WAIT
10.0.0.5:6000
10.0.0.11:45001
TIME-WAIT
10.0.0.5:6000
10.0.0.12:45002이런 상태를 볼 수 있습니다.
20장 TCP 상태는 개수보다 추세를 본다#
한 번 조회해서:
TIME_WAIT 300개를 봤다고 바로 장애라고 판단하면 안 됩니다.
다음과 같이 시간에 따른 변화를 보는 것이 더 중요합니다.
10:00
TIME_WAIT 120
10:05
TIME_WAIT 180
10:10
TIME_WAIT 110
10:15
TIME_WAIT 160처럼 증가와 감소를 반복한다면 정상적인 Traffic 패턴일 수 있습니다.
반대로:
10:00
CLOSE_WAIT 100
10:05
CLOSE_WAIT 300
10:10
CLOSE_WAIT 700
10:15
CLOSE_WAIT 1500처럼 계속 누적된다면 Application 처리를 확인해야 합니다.
21장 TIME_WAIT가 많은 이유를 먼저 찾는다#
TIME_WAIT를 무조건 줄이려고 Kernel Parameter부터 바꾸는 것은 좋지 않습니다.
먼저 질문해야 합니다.
왜 이렇게 많은 Connection을
짧게 만들고 닫고 있는가?예를 들어 Application이 요청마다:
Connect
↓
Request
↓
Response
↓
Close를 반복하고 있을 수 있습니다.
가능하다면 Protocol과 Application 특성에 따라 Connection 재사용을 검토할 수 있습니다.
예:
HTTP Keep-Alive
Connection Pool
Persistent TCP Connection등입니다.
22장 TCP Keepalive와 Connection 종료는 다른 문제다#
TCP Keepalive는 오래 동안 Traffic이 없는 Connection에서 상대방이 여전히 존재하는지 확인하는 데 사용할 수 있는 기능입니다.
개념적으로:
ESTABLISHED
↓
오랫동안 Traffic 없음
↓
Keepalive Probe
↓
상대 응답 여부 확인입니다.
22.1 Keepalive가 Connection Leak을 자동으로 해결하는 것은 아니다#
Application이 이미 상대의 FIN을 받아:
CLOSE_WAIT상태인데 Socket을 닫지 않고 있다면 Keepalive가 해결책이 아닙니다.
CLOSE_WAIT는:
Application close 처리가 필요한 문제입니다.
따라서:
CLOSE_WAIT 증가
→ Keepalive 짧게 설정으로 해결하려는 접근은 적절하지 않을 수 있습니다.
23장 Application Timeout도 TCP Keepalive와 다르다#
예를 들어 주차관제 Protocol에서:
30초 동안 Heartbeat 없음
→ 장비 Offline 처리라는 정책을 사용할 수 있습니다.
이것은 Application 수준의 상태 판단입니다.
TCP Keepalive는 TCP Stack 수준입니다.
Application Heartbeat
→ 업무 Application 상태 확인
TCP Keepalive
→ TCP Peer 생존 여부 확인 보조서로 목적이 다릅니다.
24장 주차관제 사례 — Camera 재부팅 후 CLOSE_WAIT가 계속 증가한다#
다음 상황을 가정해보겠습니다.
Camera 100대
↓
TCP
↓
Image ServerCamera Firmware Update 후 여러 Camera가 순차적으로 재부팅되었습니다.
Server를 확인했더니:
CLOSE_WAIT 12
CLOSE_WAIT 48
CLOSE_WAIT 103
CLOSE_WAIT 231처럼 계속 증가합니다.
24.1 Packet Capture를 확인한다#
Camera가 재부팅 전에 정상적으로 FIN을 보냈다고 가정하겠습니다.
Camera
FIN
──────→ Server
Server
ACK
←──────Server TCP Stack은 정상적으로 FIN을 받았습니다.
그러나 Server Application이 해당 Socket을 닫지 않습니다.
결과:
Remote FIN 수신
↓
CLOSE_WAIT
↓
Application close() 없음
↓
CLOSE_WAIT 계속 유지입니다.
24.2 이 경우 Network가 원인은 아닐 수 있다#
이 상태에서 Switch나 Cable을 교체해도 문제가 해결되지 않습니다.
확인해야 할 것은:
Socket 종료 Code
Exception 처리
Thread Lifecycle
Connection Manager
Library 사용 방식입니다.
CLOSE_WAIT는 Network 문제와 Application 문제를 구분하는 좋은 단서입니다.
25장 주차관제 사례 — 장비 전원 OFF 후 연결이 오래 남는다#
이번에는 Gate Controller 전원이 갑자기 끊겼다고 가정합니다.
Controller는 FIN이나 RST를 보내지 못했습니다.
Server 입장에서는 즉시 알 수 없을 수 있습니다.
Server
ESTABLISHED
Controller
Power OffTraffic이 없다면 이런 상태가 일정 시간 유지될 수도 있습니다.
이 경우:
Application Heartbeat
Read Timeout
TCP Keepalive
Device Status Monitoring같은 구조가 장애 감지에 중요합니다.
26장 주차관제 사례 — RST가 계속 발생한다#
Packet Capture:
Controller → Server
SYN
Server → Controller
SYN/ACK
Controller → Server
ACK
Controller → Server
Data
Server → Controller
RST이 경우 Server가 Connection을 강제로 종료한 것처럼 보입니다.
확인할 항목은:
Server Application Log
Protocol Parsing Error
Connection 정책
Idle Timeout
Firewall / Load Balancer
Server Restart 여부등입니다.
RST 하나만 보고 Cable 문제라고 판단하면 안 됩니다.
27장 방화벽과 Load Balancer도 TCP 상태를 관리할 수 있다#
Stateful Firewall이나 Load Balancer는 TCP Connection 상태를 추적하는 경우가 많습니다.
예를 들어:
Client
↓
Firewall
↓
Server구조에서 Firewall의 Session Timeout이 Server나 Client보다 짧을 수 있습니다.
오랫동안 Traffic이 없으면:
Firewall Session 제거가 발생할 수 있습니다.
이후 Client가 기존 Connection이라고 생각하고 데이터를 보내면 예상하지 않은 장애가 발생할 수 있습니다.
따라서 장시간 유지되는 TCP Connection에서는:
Client Timeout
Server Timeout
Firewall Session Timeout
Load Balancer Timeout을 함께 비교해야 합니다.
28장 FIN이 보이지 않는다고 반드시 이상한 것은 아니다#
Packet Capture 위치가 중간이라면 모든 Packet을 볼 수 있다는 보장이 없습니다.
예:
Mirror Port Drop
Capture 시작 전에 FIN 발생
다른 Routing Path 사용
NIC Offloading
Capture Filter 오류등이 있을 수 있습니다.
따라서:
FIN이 Capture에 없다
=
상대가 FIN을 보내지 않았다라고 무조건 단정해서는 안 됩니다.
필요하면 양쪽 Endpoint에서 확인합니다.
29장 정상 종료와 강제 종료를 비교해보자#
| 구분 | 정상 종료 | 강제 종료 |
|---|---|---|
| 대표 Flag | FIN·ACK | RST |
| 목적 | 데이터 전송을 정상적으로 마침 | Connection 즉시 중단 |
| Half-Close | 가능 | 일반적인 정상 절차 아님 |
| 상태 전이 | FIN_WAIT·CLOSE_WAIT·TIME_WAIT 등 | 빠른 Reset |
| 현장 의미 | 정상 Application 종료 가능 | 오류·정책·강제 종료 등 원인 확인 필요 |
RST가 있다고 반드시 장애라는 뜻은 아니지만 왜 Reset됐는지 확인해야 하는 중요한 단서입니다.
30장 TCP 상태별 현장 판단 기준#
| 상태 | 의미 | 오래 지속될 때 확인 |
|---|---|---|
| ESTABLISHED | 연결된 상태 | 실제 Traffic·Heartbeat 여부 |
| FIN_WAIT_1 | FIN 전송 후 ACK 대기 | Packet Loss·상대 상태 |
| FIN_WAIT_2 | FIN ACK 후 상대 FIN 대기 | 상대 Application 종료 여부 |
| CLOSE_WAIT | 상대 FIN 수신, Local close 대기 | Application Socket close |
| LAST_ACK | Local FIN 후 ACK 대기 | 상대 응답·Network |
| TIME_WAIT | 종료 후 일정 시간 상태 유지 | Connection 생성률·Port 사용 |
| LISTEN | 연결 요청 대기 | 정상적인 Server 상태 |
| CLOSED | 연결 없음 | 정상 |
31장 tcpdump로 FIN과 RST 확인하기#
시험망이나 허가된 환경에서는:
tcpdump -n -i eth0 'tcp port 6000'처럼 확인할 수 있습니다.
FIN을 포함한 Packet은 예를 들어:
Flags [F.]처럼 보일 수 있습니다.
RST는:
Flags [R]또는:
Flags [R.]처럼 나타날 수 있습니다.
31.1 특정 Host까지 제한하기#
tcpdump -n -i eth0 'host 10.0.0.5 and tcp port 6000'처럼 범위를 좁히면 불필요한 Traffic과 민감정보 수집을 줄일 수 있습니다.
32장 Wireshark에서는 무엇을 확인할까#
종료 문제를 분석할 때 다음 순서로 보면 좋습니다.
32.1 누가 먼저 FIN을 보냈는가#
Active Close를 시작한 Endpoint를 확인합니다.
32.2 FIN에 ACK가 돌아왔는가#
FIN Packet Loss 또는 Return Path 문제를 확인하는 데 도움이 됩니다.
32.3 상대방도 FIN을 보냈는가#
한쪽 Application이 Connection을 계속 유지하고 있는지 볼 수 있습니다.
32.4 RST가 있다면 누가 보냈는가#
Source IP와 Capture 위치를 확인합니다.
중간 장비가 생성했을 가능성도 고려해야 합니다.
32.5 마지막 Packet 이후 Socket 상태는 무엇인가#
Packet Capture와 ss 결과를 같은 시간에 비교하면 더욱 정확합니다.
33장 시험망에서 정상 종료를 관찰해보자#
33.1 간단한 TCP Server#
시험망에서:
nc -l 7000처럼 Listener를 준비합니다.
nc 구현에 따라 Option은 다를 수 있습니다.
33.2 Client 연결#
nc 192.0.2.10 7000으로 연결합니다.
동시에:
tcpdump -n -i eth0 'tcp port 7000'을 실행합니다.
33.3 정상 종료 관찰#
Client를 정상적으로 종료하고:
FIN
ACK
FIN
ACK흐름이 어떻게 나타나는지 확인합니다.
그리고 양쪽에서:
ss -tan을 실행해 상태 변화를 관찰합니다.
34장 CLOSE_WAIT 실습은 Application Code로 이해하는 것이 좋다#
CLOSE_WAIT를 이해하려면 Server가 상대 FIN을 받은 뒤 Socket을 닫지 않는 상황을 만들 수 있습니다.
개념적인 흐름은:
Client 종료
↓
Server FIN 수신
↓
Server ACK
↓
Server Application은 Socket close 안 함
↓
CLOSE_WAIT 유지입니다.
이 실습은 반드시 분리된 시험 환경에서 진행하고 실제 관제 Server에 의도적인 Resource Leak을 만들면 안 됩니다.
35장 Connection Leak을 진단할 때 함께 볼 지표#
Socket 상태만 보지 말고 다음을 함께 확인하는 것이 좋습니다.
TCP State별 개수
Process File Descriptor 수
Process Memory
Thread 수
Connection 생성률
Connection 종료률
Application Error Log예를 들어:
CLOSE_WAIT 증가
+
FD 증가
+
Memory 증가가 동시에 나타난다면 매우 중요한 증거입니다.
36장 무작정 TCP Kernel 설정부터 바꾸지 않는다#
장애가 발생했을 때 다음과 같이 접근하기 쉽습니다.
TIME_WAIT 많음
↓
TIME_WAIT 시간 줄이기
CLOSE_WAIT 많음
↓
Keepalive 짧게 만들기하지만 이렇게 하면 원인을 가릴 수 있습니다.
먼저:
누가 Connection을 만드는가?
누가 먼저 닫는가?
FIN은 정상적으로 오가는가?
어떤 TCP State가 증가하는가?
Application이 close를 호출하는가?를 확인해야 합니다.
설정 변경은 원인을 확인한 뒤 해야 합니다.
37장 TCP 종료와 Application Protocol을 연결해서 봐야 한다#
예를 들어 Server가 Response를 보내자마자 Connection을 닫는 Protocol이라면:
Request
↓
Response
↓
FIN이 정상일 수 있습니다.
반대로 장시간 Persistent Connection을 유지하도록 설계된 장비에서 매 요청마다 Connection이 끊긴다면 비정상일 수 있습니다.
따라서:
FIN이 많다
=
장애라고 할 수 없습니다.
Application Protocol이 Connection을 어떻게 사용하도록 설계되어 있는지를 알아야 합니다.
38장 TCP 종료 장애 진단 순서#
38.1 현재 TCP 상태 확인#
ESTABLISHED?
CLOSE_WAIT?
TIME_WAIT?
FIN_WAIT?를 확인합니다.
38.2 Packet Capture 확인#
FIN을 누가 보냈는가?
ACK가 왔는가?
상대 FIN이 왔는가?
RST가 있는가?를 확인합니다.
38.3 Application Log 확인#
Socket Close
Connection Error
Exception
Timeout
Process Restart등을 확인합니다.
38.4 중간 장비 확인#
Firewall Session Timeout
NAT Session
Load Balancer
VPN을 확인합니다.
38.5 Resource 상태 확인#
File Descriptor
Memory
Thread
Socket Count
Ephemeral Port를 확인합니다.
39장 증상별로 원인을 좁혀보자#
| 증상 | 우선 확인 |
|---|---|
| CLOSE_WAIT 지속 증가 | Application close 누락 |
| TIME_WAIT 많음 | Connection 생성·종료 패턴 |
| FIN_WAIT_1 장기 지속 | FIN ACK 손실·상대 상태 |
| FIN_WAIT_2 장기 지속 | 상대 Application이 FIN을 보내는지 |
| RST 반복 | Application·Firewall·Load Balancer |
| ESTABLISHED만 오래 남음 | Heartbeat·Keepalive·Timeout 정책 |
| 새 Connection 실패 | FD·Port·Memory·Listen Queue |
| 장비 재부팅 후 오래된 연결 잔존 | Keepalive·Heartbeat·Session Timeout |
40장 자주 발생하는 오해#
40.1 TIME_WAIT는 Connection Leak이다?#
아닙니다.
TIME_WAIT는 정상 TCP 종료 과정에서 필요한 상태입니다.
과도한 개수가 실제 Resource 문제를 만드는지는 Connection 패턴과 Endpoint 역할을 함께 봐야 합니다.
40.2 CLOSE_WAIT는 Network가 Socket을 안 닫아서 발생한다?#
일반적으로 CLOSE_WAIT는 Local Application이 Socket 종료 처리를 기다리는 상태입니다.
오래 누적된다면 Application을 우선 확인해야 합니다.
40.3 장비가 비정상 종료되면 반드시 RST를 보낸다?#
아닙니다.
전원 장애처럼 Packet을 보낼 기회가 없는 경우 아무 종료 Packet도 보내지 못할 수 있습니다.
40.4 FIN을 보내면 바로 양방향 연결이 끝난다?#
아닙니다.
FIN은 해당 방향의 전송 종료를 의미하며 TCP는 Half-Close가 가능합니다.
40.5 RST가 보이면 공격이다?#
아닙니다.
닫힌 Port, Application 강제 종료, Firewall 정책 등 정상적이거나 운영상의 여러 이유로 RST가 발생할 수 있습니다.
41장 핵심 개념 한눈에 정리하기#
| 개념 | 핵심 의미 |
|---|---|
| FIN | 한 방향의 정상적인 데이터 전송 종료 |
| ACK | FIN 등 상대 Segment 수신 확인 |
| RST | Connection 즉시 Reset |
| Half-Close | 한 방향만 먼저 종료된 상태 |
| FIN_WAIT_1 | FIN을 보내고 ACK 대기 |
| FIN_WAIT_2 | FIN ACK 후 상대 FIN 대기 |
| CLOSE_WAIT | 상대 FIN 수신 후 Local Application close 대기 |
| LAST_ACK | Local FIN 후 마지막 ACK 대기 |
| TIME_WAIT | 종료 후 일정 시간 Connection 정보 유지 |
| Connection Leak | Application이 불필요한 Socket Resource를 정리하지 못하는 문제 |
| TCP Keepalive | 유휴 Connection의 Peer 상태 확인 보조 |
| Application Heartbeat | 실제 Application의 응답 상태 확인 |
42장 자기 점검#
42.1 FIN은 무엇을 의미하는가#
해당 Endpoint가 그 방향으로 더 이상 보낼 데이터가 없다는 의미입니다.
반대 방향의 데이터 전송까지 즉시 종료한다는 뜻은 아닙니다.
42.2 CLOSE_WAIT가 계속 증가한다면 무엇을 먼저 확인할까#
Local Application이 상대의 FIN을 받은 뒤 Socket을 정상적으로 닫고 있는지 확인합니다.
42.3 TIME_WAIT는 왜 필요한가#
마지막 ACK가 유실됐을 때 재전송된 FIN에 다시 대응할 수 있고, 이전 Connection의 지연된 Segment가 새로운 Connection에 섞이는 위험을 줄이는 데 필요합니다.
42.4 RST가 보이면 무엇을 확인해야 할까#
먼저 누가 RST를 보냈는지 확인합니다.
그다음:
Application
Listening Port
Firewall
Load Balancer
Connection 상태등을 확인합니다.
42.5 장비 전원이 갑자기 꺼졌는데 Server에 ESTABLISHED Socket이 남아 있는 것은 가능한가#
가능합니다.
장비가 FIN이나 RST를 보내지 못했다면 Server가 즉시 장애를 알지 못할 수 있습니다.
Application Heartbeat, Timeout 또는 TCP Keepalive 등이 이후 장애를 감지하는 데 사용될 수 있습니다.
43장 이 글을 마치며#
TCP Connection은:
SYN
↓
SYN/ACK
↓
ACK
↓
ESTABLISHED로 시작하지만 종료는 단순히 Connection을 지우는 과정이 아닙니다.
정상적인 종료에서는:
FIN
↓
ACK
↓
FIN
↓
ACK과 같은 과정이 나타날 수 있습니다.
그리고 그 과정에서 각 Endpoint는 서로 다른 상태를 거칩니다.
FIN을 먼저 보낸 쪽
ESTABLISHED
↓
FIN_WAIT_1
↓
FIN_WAIT_2
↓
TIME_WAIT
↓
CLOSED상대 FIN을 먼저 받은 쪽은:
ESTABLISHED
↓
CLOSE_WAIT
↓
LAST_ACK
↓
CLOSED처럼 진행할 수 있습니다.
따라서 현장에서 Socket 상태를 볼 때 단순히:
Socket이 많이 남아 있다.고 판단해서는 안 됩니다.
먼저:
어떤 상태가 많은가?
누가 먼저 FIN을 보냈는가?
상대 FIN은 도착했는가?
Application이 close했는가?
RST는 누가 보냈는가?
Connection 생성 속도는 얼마인가?
Resource가 실제로 고갈되고 있는가?를 확인해야 합니다.
특히 다음 네 가지를 기억하면 TCP 종료 문제를 훨씬 정확하게 판단할 수 있습니다.
FIN은 Connection 전체의 즉시 종료가 아니라 한 방향의 정상적인 전송 종료를 의미합니다.
CLOSE_WAIT가 오래 누적되면 Local Application의 Socket 종료 처리를 우선 확인해야 합니다.
TIME_WAIT는 TCP의 정상적인 안전장치이며 존재 자체가 Connection Leak을 의미하지 않습니다.
RST는 강제적인 Connection Reset이지만 원인은 Application·운영체제·Firewall·Network 장비 등 다양할 수 있습니다.
TCP 종료 장애를 제대로 분석하려면 결국:
Packet
+
TCP State
+
Application Log
+
System Resource를 같은 시간축으로 연결해야 합니다.
이 네 가지를 함께 보면 연결이 안 끊긴다, 새 연결이 안 들어온다, RST가 계속 발생한다 같은 모호한 증상을 실제 원인으로 좁혀갈 수 있습니다.