4 way hand shake
- 정상종료의 상태. 정상적으로 종료 절차를 밟는 것.
https://steffen-lee.tistory.com/31
과정
1. 클라가 FIN을 보낸다.
- FIN의 의미는?
- 연결 끊자가 아니다.
- 내가 너한테 보낼게 없다라는 것. 나는 보낼 메시지가 없다는 것.
- 그럼 recv의 리턴이 0이라는 건, FIN을 받은 것이다.
- FIN을 보냈어도 더 보낼게 있으면 더 보내도 된다.
- 근데 보통은 상대방이 FIN보내고 close socket으로 닫는데, 그럼 나머지 데이터를 못받는다.
- 그럼 상대방은 어, 쟤가 recv 0이네 하고 보낼 게 있으면 보내고 중단한다.
- 이걸 graceful shutdown이라고 한다. 아름다운 셧다운 절차대로. 4 way hand shake를 우리 코드상으로 진행하는 것. TCP는 이 절차를 따르는데, 일사천리로 하는게 아니라 우리가 코드로 제어하는게 아름다운 셧다운이다.
- close socket의 행동
- 1. 연결 종료를 요청하는 FIN을 보내는 역할 (4 way hand shake의 첫번째 단계 도입)
- 2. 소켓 리소스를 반환하는 역할. 소켓을 반환했다고 netstat 에서 바로 사라지는게 아니다.
- 대표적으로 TIME_WAIT 같은 것.
- close socket의 이후의 단계다.
- 이게 어떻게 끊길지는 다른이야기고, 잘 마무리가 되는건 TCP가 할 일이다.
- 근데 셧다운(shutdown(SD_SEND))은? 리소스를 반환하는 행위를 뺀 것이다.
- 셧다운은 소켓 리소스를 반환하지 않고, 연결종료의 절차만 진행시킬 수 있는 애.
- FIN만 보낸다. SD_RECV를 받지 않겠다는 것. 근데 이게 되나?
- 보내지 않겠다는 있어도, 받지 않겠다는 없다.
- 사실 이건 하는 일이 없다. 이거 한 다음에 recv 함수는 에러가 난다. 받지 않겠다 했으니까.
2, 3. 상대방이 OK, 받았어! 하고 답장으로 ACK를 보낸다. 그리고 보낼 데이터를 마저 보낸다.
- 여기까지 하면 절반만 끊기가 된다.
- 그럼 받은쪽에서는 0이 왔으니까 보낼게 있으면 보내고, 보낸 쪽에서는 받을거 받고 소켓을 닫는다.
- 이 과정이 graceful shutdown.
- 상대가 FIN 보냈네, 끊어야지! 이게 아니라, 아 쟤가 끊으려나 보다 보낼거 마저 보내야지. 하고 ACK를 보낸다
- 그럼 끊는쪽도 마지막으로 오는 거 있는지 확인차 recv 걸어주고
- 이 recv 결과로 0(FIN)이 나오면 아, 상대방도 보낼게 없구나 하고 끊는 것이 절차다.
4. 끊는 쪽에서 확인차 RECV 후, ACK
- 그럼 끊는쪽도 마지막으로 오는 거 있는지 확인차 recv 걸어주고
- 이 recv 결과로 0(FIN)이 나오면 아, 상대방도 보낼게 없구나 하고 끊는 것이 절차다.
4 way hand shake의 필요성
이렇게 하면 아름답게 종료하는 graceful shutdown의 절차인데, 이렇게까지 할 필요가 있을까? 끄려고 하는 상황인데, 마지막까지 보내야할 게 있을까?? DB에 저장되어 있으면 되는데 뭐 굳이 알려줄 필요가 없다. 그래서 이론적으로 존재하는 것. 우리는 굳이 이렇게 할 필요는 없다. 하지마라. 그래도 각각의 상태에 대한 건 외워야 한다.
- FIN_WAIT_1에서 FIN을 보내면, 상대는 CLOSE_WAIT가 되고... 결국 TIME_WAIT 상태까지. 이런걸 왜 알아야 할까?
- 서버에 잔재가 남기 때문이다.
- 서버쪽 포트가 FIN_WAIT_1 상태로 남는다?
- 그럼 이건 FIN을 보냈는데 상대방으로부터 ACK 응답이 안오는 상황이다.
- 왜 응답이 안올까?
- 랜선이 끊길수도, 공유기가 끊길수도, FIN이 유실됐을수도 있다.
- 그럼 영원히 전달이 안된다.
- 전달이 돼도 상대가 먹통이 돼서 응답을 안하는 경우다.
- 또 FIN_WAIT_2가 남는 경우?
- recv 0이 떨어졌는데, 그 다음 소켓을 닫든 뭘 해줘야 하는데 그걸 안하면 FIN_WAIT_2가 남는다.
- 또 TIME_WAIT
- 마지막에 남는 거다.
- 이것도 잔재가 남는다.
- 이건 무조건 첫번째 FIN을 보낸 연결을 먼저 끊은 애한테 남는다.
- 거의 윈도우 기준 20~30초 정도 된다.
- 이 상태로 그만큼 살아있는 상태다.
- 필요해서 이 개념이 나왔을텐데, 왜 필요한가???
- 연결 종료 후 바로 포트 파괴하고 정리하면 어떤 문제가 있는가?
- IP라는 구조상 메세지가 순서가 지켜지지도 않고, 우회해서 오기도 한다.
- FIN을 받았지만, 그것보다 먼저 보낸 데이터가 늦게 돌아오느라 아직 안왔을수도 있다는 것.
- 이런 상황에서 포트를 없애면 누군가는 그 포트를 사용하게 되고, 전에 애한테 보냈어야 하는 데이터가 잘못 도착할수도 있다.
- 그래서 나온게 TIME_WAIT 상태다.
- IP 프로토콜의 문제점. 순서보장이 없기 때문에.
- 그래서 포트를 못쓰게 잠궈두는 상태가 TIME_WAIT이다.
- 서버는 TIME_WAIT가 남는걸 걱정한다.
- 왜? 들락날락이 많아서.
- 물론 클라가 먼저 끊으면 클라쪽에 TIME_WAIT가 남으니 상관이 없다.
- 그럼 언제 문젠가????
- 불필요한 연결이 대량으로 들어오는 경우.
- 우린 이걸 공격으로 간주하고 끊어내는데, 몇초만에 TIME_WAIT 포트가 우루루루 생겨서 몇만개가 된다?
- 이 때 문제는??
- TIME_WAIT 상태의 의미는 재사용 방지다.
- 그럼 평생을 못쓸까?? 클라이언트면 맞다. 랜덤포트로 돌리는데 사용중이라 클라는 못쓰게 된다.
- 그럼 서버는?? 포트를 쓴다는건 바인딩을 해서 내가 이 포트를 쓰겠다는 것이다.
- TIME_WAIT가 남으면 우리쪽 포트는 다 9000으로 남는다. 그렇다고 해서 우리가 9000번 포트를 못쓰는게 아니다.
- 그럼 뭐가 문제인가????
- 리소스가 문제다.
- 남는 TCP 연결 정보마다 nonpaged가 된다. 그럼 이 정보가 남을때마다 서버쪽 리소스에 문제가 생길 가능성이 올라간다.
- 그래서 서버는 필수적으로 TIME_WAIT가 안남도록 유도한다.
- 그래서 서버는 TIME_WAIT을 안하는데, 그럼 처음에 TIME_WAIT을 쓰게 된 원인같은 문제는 없나?
- 없다. 같은 IP, 포트, 게다가 시퀀스 번호까지 같아야 하는 그 패킷을 받을 확률은 거의 없다.
- IP, 포트번호 같아도 시퀀스가 다르면 폐기한다.
- TIME_WAIT을 안 남게 하는 방법은?
- 4 way hand shake를 안 하는 것.
- 한번이라도 FIN을 보내면 일단 돌입한거라 중단이 안된다.
- 안하는 유일한 방법은? RST를 보내서 연결을 즉각적으로 파괴해야한다.
- 이것 말고는 방법이 없다.
- 소켓 옵션을 통해 세팅하고, close socket을 통해 4way hand shake를 무시하고 파괴하는 걸 해야한다.
출처: https://popcorntree.tistory.com/112 [어떤 프로그래머]
'⚡네트워크' 카테고리의 다른 글
VMware Network Editor 통한 가상머신 네트워크 정의 (0) | 2021.02.19 |
---|---|
DNS에서 CNAME과 A 레코드의 차이 (0) | 2021.01.30 |
TCP-3-WayHandshake-4-WayHandshake (0) | 2020.12.17 |
프로비저닝(Provisioning)이란? (0) | 2019.10.21 |
네트워크 장비 성능 관련 용어 - CPS (Connections Per Second) (0) | 2019.09.23 |