안녕하세요 쿤드입니다. 🍀
RFC 793에 나와있는 상태도를 바탕으로 하나씩 따라가면서 확인하면 보입니다.
python2로 구현된 간단한 tcp client/server 코드와 함께 확인해보겠습니다.
* TCB: Transmission Control Block
ESTABLISHED까지는 1가지 경우인데
종료할때는 2가지 case로 나뉩니다. RFC793 Link
- Normal Close(일반 종료): FIN-WAIT-1 ➡️ FIN-WAIT-2 ➡️ TIME-WAIT
- Simultaneous close(동시 종료): FIN-WAIT-1 ➡️ CLOSING ➡️ TIME-WAIT
일반 종료 - 어느 한쪽에서 종료하기 위해 FIN을 날린 경우 |
동시 종료 - Clinet, Server 양쪽에서 동시에 FIN을 날린 경우 |
Python Code로 테스트 (Code link)
Server | Client |
Server쪽에서 일반 종료인 경우 netstat으로 확인해서 보았습니다.
Server에서 socket() 열고, bind()하고 listen() 함수 호출해서 Listening을 하면
tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN 8268/python off (0.00/0/0)
Client에서
connect() 호출하면
tcp 0 0 SERVER_IP:9999 CLIENT_IP:36391 ESTABLISHED 8268/python off (0.00/0/0)
send(), recv() 호출 이후 종료
tcp 0 1 SERVER_IP:9999 CLIENT_IP:36391 FIN_WAIT1 - on (0.17/0/0)
tcp 0 0 SERVER_IP:9999 CLIENT_IP:36391 FIN_WAIT2 - timewait (8.99/0/0)
tcp 0 0 SERVER_IP:9999 CLIENT_IP:36391 FIN_WAIT2 - timewait (7.97/0/0)
tcp 0 0 SERVER_IP:9999 CLIENT_IP:36391 TIME_WAIT - timewait (59.90/0/0)
tcp 0 0 SERVER_IP:9999 CLIENT_IP:36391 TIME_WAIT - timewait (58.88/0/0)
tcp 0 0 SERVER_IP:9999 CLIENT_IP:36391 TIME_WAIT - timewait (57.86/0/0)
CLOSE_WAIT 상태는 상태도만 봤을때 이해가 잘 안가서 Server/Receiver 쪽에서 억지로 재현해보았습니다.
- Client/Sender에서 ESTABLISHED 이후에 data를 보냄
- Server/Receiver에서 'ACK!' 라고 응답 (60sec 대기)
- Client/Sender에서 data를 보냄
- Server/Receiver는 여저히 sleep으로 대기상태
# 서버쪽 응답하는 thread 코드
def handle_client_connection(client_socket):
while True:
request = client_socket.recv(1024)
print 'Received {}'.format(request)
print 'send ack & sleep'
try:
client_socket.send('ACK!')
time.sleep(60) # <--- 여기서 막음
except socket.error as error:
break
client_socket.close()
- 이때 Client/Sender는 응답을 못 받아서 대기중인 상태인데 강제로 종료 (Ctrl + C, KeyboardInterrupt)
이렇게 하는 경우 또 다른 client에서 붙고 마찬가지로 멈춰버린 상태에서 client process 강제 종료
tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN 17043/python off (0.00/0/0)
tcp 54 0 SERVER_IP:9999 CLIENT1_IP:39099 CLOSE_WAIT 17043/python off (0.00/0/0)
tcp 54 0 SERVER_IP:9999 CLIENT2_IP:47657 CLOSE_WAIT 17043/python off (0.00/0/0)
이 예시에서는 sleep 60으로 60s 지나면 해소가 되는데
Deadlock이라도 걸려서 저 상태가 계속해서 지속되면 결국엔 CLOSE_WAIT이 쌓여서 사용 가능한 PORT를 전부 사용하게 될테고
서버가 행업이 됩니다.
저 상태에서 Server side가 close를 호출하지 못하면 CLOSE_WAIT은 자동으로 사라지지도 않습니다.
이것이 실제 production 환경에서 발생한다면
dead lock 걸린 부분을 찾아서 소스 코드를 수정하기 전까지는
시스템 엔지니어는 주기적으로 CLOSE_WAIT 개수를 체크해서 서버 프로세스를 재시작해주면서 버티는 방법밖에는 없어보입니다.
'기타' 카테고리의 다른 글
Python3를 이용한 Tistory Authentication Code 방식 인증 (2020.09.01 변경사항 반영) (2468) | 2020.09.25 |
---|---|
테넌트 (940) | 2020.07.23 |
TCP 통계수치 변화 (장애 상황) (1318) | 2020.07.15 |
TCP 통계 (445) | 2020.07.14 |
Kerberos Setup (KR) (1401) | 2019.08.22 |