달력

4

« 2024/4 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
.. .. ..

[펌] : http://kldp.org/node/165

 댓글들을 정리하였습니다.

 

 

첫번째 정리

 

예전에 제가 TIME_WAIT 상태에 대해 정리했던 글입니다. 한번 읽어보시길 바랍니다.
Unix나 Linux 상에서 네트워크 프로그래밍을 하실때는 W.Richard Stevens가 저술한 Unix Network Programming을 참고하시면
많은 도움이 됩니다.(유닉스 네트워크 프로그래밍 서적의 바이블이죠.)

Quote:
TCP는 여러개의 State를 가질수 있습니다. 예를들어 CLOSED(연결이 닫혔을때) LISTEN(연결을 기다리고 있을때), ESTABLISHED(연결이 되었을때) 등등의 상태를 가질수 있습니다. 이중에서 TIME_WAIT라는 상태가 있는데, 이해하기 가장 어려운 부분인것 같습니다. TIME_WAIT 상태는 다음과 같은 경우에 발생합니다. 우선 Client와 Server가 TCP로 연결이 되어 있다고 가정합시다. 이때 클라이언트가 연결을 끊으려면 close함수를 호출합니다. 이 함수를 호출하면 서버에 FIN segment를 보내게 됩니다. 그러면 서버는 이 메시지를 받고 클라이언트가 접속을 끊으려고 하는 것을 알게됩니다. 따라서 서버가 CLOSE_WAIT 상태가 되면서 클라이언트에게 ack segment를 보냅니다. 즉 "네가 접속을 끊는 다는 신호를 받았다" 이런 의미입니다. 이 메시지를 받으면 클라이언트는 FIN_WAIT_2 상태가 됩니다. 이 상태에서 서버는 자신의 socket을 close하고 다시 클라이언트에게 FIN segment를 보냅니다. 즉 자신도 연결을 닫았다는 신호를 클라이언트에게 보내는 것입니다. 이 메시지를 받으면 클라이언트는 ack segment를 보내면서 TIME_WAIT 상태가 됩니다. 즉 서로간의 확인하에 완전히 연결이 끊기게 됩니다. 근데 이 상태에서 곧바로 CLOSED 상태가 되는 것이 아니라 2 MSL(maximum segment lifetime - 1분~4분) 동안 TIME_WAIT상태를 유지합니다. 왜 곧바로 CLOSED 상태가 되지 않고 일정시간 동안 TIME_WAIT 상태가 되는 것일까요?

뭔가 이상하지 않습니까? 그 이유는 다음과 같습니다. TCP는 신뢰성을 보장해 주는 프로토클 입니다.(UDP는 아니지요.) 따라서 연결시에도 신뢰성을 보장하기 위하여 Three-way handshake라는 기법을 사용하여 연결을 하고 종료시에도 위와같이 복잡한 과정을 거쳐 서로가 close된것을 확인하게 되는 것입니다. TIME_WAIT 상태도 이와같은 신뢰성 보장을 위한 한가지 방법이라고 보시면 됩니다.

Unix Network Programming에 보면 TIME_WAIT 상태가 있는 이유에 대해 다음과 같이 설명하였습니다.

1. to implement TCP's full-duplex connection termination reliably, and
2. to allow old duplicate segments to expire in the network.

흠 첫번째는 신뢰성있는 연결 종료를 위한 것이라고 쓰여있습니다. 근데 두번째는 무엇일까요?
network에 있는 duplicate segments들이 소멸시키기 위해서?? 무슨 소리인지 -_-;;
이 두가지에 대하여 자세히 설명해 보겠습니다.

 

먼저 첫번째에 대해서 설명하겠습니다.
이것은 말그대로 신뢰성있은 연결 종료를 위한것입니다. 다음과 같은 상황을 가정합시다. 클라이언트가 FIN_WAIT_2 상태에서 서버의 FIN segment를 받으면 TIME_WAIT상태가 되면서 서버에 ack segment를 보낸다고 하였습니다. 하지만 이 ack segment가 네트워 크의 오류로 인해 서버에 도착하지 못할수도 있습니다. 그런 경우라면 서버에서는 일정시간 이후에 다시 클라이언트에게 FIN segment를 보냅니다. 자신이 응답을 못받았으니 다시 보내달라는 의미지요. 만약 클라이언트가 CLOSED 상태 즉 연결이 닫혀 있는 상태에서 서버가 다시 보낸 이 FIN segment를 받으면 어떻게 될까요? 그런 경우라면 ack대신 RST라는 segment를 보내게됩니다. 즉 CLOSED 되면서 이전에 서버와 연결했던 정보들이 전부 없어졌으므로 서버가 다시 요청을 하면 "나는 너를 모른다. 왜 이상한 메시지를 보내느냐?" 하면서 서버가 원하는 ack 대신 RST라는 segment를 보내게 되는 것입니다. 이런 상황을 방지하기 위하여 일정시간 동안 TIME_WAIT라는 상태를 유지하여 서버가 다시 FIN을 보냈을때 대답할수 있게 해줍니다.

 

두번째에 대한 설명입니다.
다음과 같은 상황을 가정해 봅시다.
우선 현재 111.111.111.111:23 번하고 111.111.111.112:1500번이 연결되어 있다고 합시다.둘이 막 패킷을 주고 받다가 둘이 연결을 정상적으로 끊었다고 가정합시다. 그 후에 둘이 곧바로 연결을 해서 방금전과 마찬가지로 111.111.111.111:23 과 111.111.111.112:1500으로 연결되었다고 합시다. 근데 여기서 문제가 발생하였습니다. 바로 이전에 연결이 성립되었을때 111번에서 112번으로 보낸 패킷하나가 라우터의 오류로 인터넷을 뺑뺑이 돌다가 이전 연결이 끊어지고 지금 새로운 연결이 되었을때 112번에 도착했습니다. 무슨 소리냐구요? 예를 들어 라우터 A와 B가 있습니다. 근데 라우터의 일시적인 오류로 라우터 A의 데이타가 B로 전송하면 B가 다시 A로 그 데이타를 전송하여 순간적인 루프에 빠질수가 있을 수도 있습니다. 이렇게 루프에 빠지던 놈이 이전 연결이 끝나고 새로운 연결이 생겼을 때 도착한다면 문제가 발생하겠죠? 즉 원하지 않는 데이타가 전송되었으니 오류가 발생할 수 도 있는 것입니다. 이것을 방지하기 위하여 TIME_WAIT 상태를 둡니다. TIME_WAIT상태에 있는 동안은 같은 연결이 발생하지 못하도록 방지합니다. 즉 이전에 내가 연결되었던 포트가 1500번이라면 다음 연결은 현재 1500번이 TIME_WAIT이므로 1501번으로 연결되게 됩니다. 그렇게 하면 위와같은 문제를 해결할 수 있습니다. 보통 TIME_WAIT상태는 2 MSL입니다. 즉 인터넷 상에서 패킷이 존재하는 시간보다 길게 설정됩니다. 그러므로 TIME_WAIT상태가 끊나면 인터넷 상에서는 이전 연결에 보내졌던 패킷이 모두 소멸되었다고 확신할 수 있으므로 새로운 연결을 만들어도 문제가 발생하지 않는것입니다..

Dream, Passion and Challenge..

 

 

두번째 정리

네트워크 프로그래밍을 하다보면 반드시, 이 문제(TIME_WAIT)를 안 겪고 넘어갈래야 안 겪고
넘어갈 수가 없습니다. 만약, 겪어보지 못했다면 공부를 다시하고 이 분야에서 충분한 경력도
없으신 분일 겁니다.. 이 TIME_WAIT 가 발생하는 문제는 심각한 문제입니다. 왜? 그러느냐?
엄청나게 빠른속도로 접속하고 엄청나게 빠른 속도로 종료되는 시스템에서는 이 TIME_WAIT 문제는
심각한 상태를 만들어냅니다.. 자원고갈되는 사태를 벌어지게 만듭니다. 위에 최초 질문자가
구현한 프로그램은 while 로 도는 무한정의 접속 및 종료의 클라이언트 연결을 만듭니다.
이런 프로그램은 포트 스캐너 같은 프로그램과 유사한 면이 있습니다. 저도 예전에 경험한 적이
있는데 수많은 접속과 종료가 순식간에 발생하면 서버 뿐만 아니라 클라이언트에서도 자원고갈이
발생합니다.. netstat 로 보게되면 TIME_WAIT 상태가 산더미 같이 쌓이게되죠.. 그럼 나중에
접속을 더이상 할 수가 없게됩니다.. 왜? 자원고갈 상태가 되어버립니다.. 소켓이 죄다 열려
있는 상태인데 사용할 포트는 65535 가 최대거든요? 이 문제가 서버에서도 발생합니다..
그래서, 클라이언트가 명확하게 접속을 끊는 경우와 서버가 명확하게 접속을 끊을 경우에는 반드시
TIME_WAIT 없이 깨끗한 상태로 끊어져야 합니다. 그래야 접속폭풍이 일어나는 기업의 상용서비스에
대응할 수 있게되는거죠.. 대기업 서버가 자원고갈이 발생해서야되겠습니까? 무식한 서버가 되는
거죠.. 그리고, 그런 문제는 자바에서는 이미 처리되고 있습니다.. 아~주 깔끔하게.. 그럼, 그게
어떻게 한거냐?

(정답)
- 서버에서 클라이언트를 명시적으로 끊었을때 TIME_WAIT 가 발생하지 않으려면..?
shutdown(sock, sd_both);
closesocket();
소켓을 닫기 전에 셧다운을 시켜야 한다. 그럼, TIME_WAIT 없이 깔끔하게 끊어진다.

- 클라이언트에서 명시적으로 끊어서 TIME_WAIT 가 발생하지 않으려면?
그건 위에 댓글 단 사람들이 이미 설명했다. SO_LINGER 써라..

-(요약)
서버에서 폭풍접속 종료에 깔끔하게 TIME_WAIT 없이 명시적 종료를 하려면 shutdown 을
쓰고, 클라이언트에서 폭풍접속 종료에 깔끔하게 TIME_WAIT 없이 명시적 종료를 하려면
SO_LINGER 에서 타임을 0 으로 바꿔라..
이렇게하는 이유는 어마어마한 속도로 접속과 종료를 반복해서 무한정 돌려야하는 클라이언트와
서버 프로그래밍에서 자원이 고갈되지 않도록(디스크립터 자원고갈 발생 방지) 하기 위함이다.
이걸 지키지 않으면 최초 접속자가 헤메는 그 증상이 나타난다. 즉, 서버와 클라이언트 양쪽
에서 이 규칙을 지켜야 합니다. 어느한쪽이 안지키면 그 안지킨 한쪽은 폭풍접속 및 종료에
있어서 결국에는 자원고갈되며 병신되는거죠..

 

 

어렵구나 네트워크는.. 에구..

 

'I.lib() > I.lib(Java)' 카테고리의 다른 글

J2EE 란?  (0) 2013.10.30
Socket 의 setTcpNoDelay 관련 정리. (Nagle 알고리즘 관련)  (4) 2013.06.17
Deque (덱) 요약  (0) 2013.06.05
[펌] ByteBuffer 설명 정리  (0) 2013.04.23
[펌] 제한자 정리  (0) 2013.04.18
.
:
Posted by .07274.