서버 측 `TIME_WAIT`는 실제로 어떻게 작동합니까?

서버 측 `TIME_WAIT`는 실제로 어떻게 작동합니까?

나는 이것에 관해 꽤 많은 SE 질문이 있다는 것을 알고 있으며, 이 지점에 도달하기 전에 중요한 만큼 많은 질문을 읽었다고 믿습니다.

"서버 측 TIME_WAIT"이란 서버 측에서 close()가 시작된 서버 측 소켓 쌍의 상태를 의미합니다.

나는 종종 나에게 모순적으로 들리는 다음 진술을 봅니다.

  1. 서버 측은 TIME_WAIT무해합니다.
  2. 클라이언트가 close()를 시작하도록 네트워크 앱을 설계해야 합니다.TIME_WAIT

내가 이 모순적이라고 생각하는 이유는 TIME_WAIT클라이언트에서 문제가 발생할 수 있기 때문입니다. 클라이언트는 사용 가능한 포트가 부족할 수 있으므로 본질적으로 위의 내용은 TIME_WAIT문제가 될 수 있는 클라이언트 측으로 부담을 옮기는 것을 권장합니다. 문제가되지 않는 서버 측.

TIME_WAIT물론 클라이언트 측은 제한된 수의 사용 사례에서만 문제가 됩니다. 대부분의 클라이언트-서버 솔루션은 하나의 서버와 여러 클라이언트를 포함하며, 클라이언트는 일반적으로 문제가 될 만큼 많은 양의 연결을 처리하지 않으며, 처리하더라도 "정상적으로"( 시간 초과가 0이거나 tcp_tw sysctls에 간섭하는 것과 반대로 너무 많은 연결을 너무 빨리 생성하는 것을 방지하여 SO_LINGER클라이언트 측과 싸우십시오 . TIME_WAIT그러나 이는 항상 가능한 것은 아닙니다. 예를 들어 다음과 같은 애플리케이션 클래스의 경우:

  • 모니터링 시스템
  • 부하 발전기
  • 프록시

반면에 나는 서버 측이 어떻게 TIME_WAIT도움이 되는지조차 이해하지 못합니다. 그 이유 는 더 이상 속하지 않는 스트림에 TIME_WAIT오래된 조각을 주입하는 것을 방지하기 때문입니다 . TCP클라이언트 측에서는 이 오래된 연결이 가질 수 있었던 것과 TIME_WAIT동일한 쌍으로 연결을 생성하는 것을 불가능하게 만들어 간단히 수행됩니다 ip:port(사용된 쌍은 에 의해 잠김 TIME_WAIT). 그러나 서버 측의 경우 로컬 주소에 허용 포트가 있고 항상 동일하며 서버는 (AFAIK, 경험적 증거만 있음) 연결을 거부할 수 없기 때문에 이를 방지할 수 없습니다. 들어오는 피어는 소켓 테이블에 이미 존재하는 동일한 주소 쌍을 생성합니다.

나는 서버측 TIME-WAIT가 무시된다는 것을 보여주는 프로그램을 작성했습니다. 게다가 테스트가 127.0.0.1에서 수행되었기 때문에 커널에는 서버 측인지 클라이언트 측인지 알려주는 특수 비트가 있어야 합니다(그렇지 않으면 튜플이 동일하기 때문).

원천:http://pastebin.com/5PWjkjEf, Fedora 22에서 테스트되었으며 기본 net 구성입니다.

$ gcc -o rtest rtest.c -lpthread
$ ./rtest 44400 s # will do server-side close
Will initiate server close
... iterates ~20 times successfully
^C
$ ss -a|grep 44400
tcp    TIME-WAIT  0      0            127.0.0.1:44400         127.0.0.1:44401   
$ ./rtest 44500 c # will do client-side close
Will initiate client close
... runs once and then
connecting...
connect: Cannot assign requested address

따라서 서버 측의 경우 TIME_WAIT정확히 동일한 포트 쌍의 연결이 즉시 성공적으로 다시 설정될 수 있으며 클라이언트 측의 경우 TIME-WAIT두 번째 반복에서는 connect()당연히 실패했습니다.

요약하면 질문은 두 가지입니다.

  • 서버 측에서는 실제로 아무 작업도 수행하지 않고 요구하기 TIME_WAIT때문에 그대로 방치되어 있습니까 ?RFC
  • TIME_WAIT서버가 쓸모 없기 때문에 클라이언트가 close()를 시작하도록 권장하는 이유는 무엇입니까 ?

답변1

~ 안에TCP여기서 서버측이라는 용어는 LISTEN 상태의 소켓을 가진 호스트를 의미합니다.

RFC1122TIME-WAIT 상태의 소켓이 일부 조건에서 새로운 연결을 허용하도록 허용합니다.

        When a connection is closed actively, it MUST linger in
        TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime).
        However, it MAY accept a new SYN from the remote TCP to
        reopen the connection directly from TIME-WAIT state, if it:

자세한 조건은 홈페이지를 참고해주세요RFC1122. 소켓(LISTEN 상태의 소켓)에도 일치하는 수동 OPEN이 있어야 한다고 예상합니다.

활성 OPEN(클라이언트 측 연결 호출)에는 이러한 예외가 없으며 소켓이 TIME-WAIT에 있을 때 오류를 제공해야 합니다.RFC793.

클라이언트(TCP 용어로 활성 OPEN, 즉 연결을 수행하는 호스트)에 대한 권장 사항에 대한 내 추측은 귀하의 것과 거의 동일합니다. 일반적인 경우 리소스가 풍부한 더 많은 호스트에 TIME-WAIT 소켓을 분산시킵니다. 소켓. 일반적인 경우 클라이언트는 서버에서 TIME-WAIT 소켓을 재사용하는 SYN을 보내지 않습니다. 나는 그러한 권장 사항을 적용하는 것이 여전히 사용 사례에 달려 있다는 데 동의합니다.

답변2

클라이언트는 알고리즘(대략 4마이크로초마다 1씩 증가)을 기반으로 하는 새로운 TCP ISN(초기 시퀀스 번호)을 사용하며, ISN은 기본적으로 항상 마지막 동일한 "ip:port 쌍" TCP 소켓에서 전송된 시퀀스 번호보다 큽니다. FIN이므로 "ip:port 쌍"이 여전히 서버에 TIME_WAIT 상태로 기록되어 있어도 서버는 항상 새 SYN을 수락합니다.

   RFC 793 [RFC0793] suggests that the choice of the ISN of a connection
   is not arbitrary, but aims to reduce the chances of a stale segment
   from being accepted by a new incarnation of a previous connection.
   RFC 793 [RFC0793] suggests the use of a global 32-bit ISN generator
   that is incremented by 1 roughly every 4 microseconds.

답변3

이것아마도 TIME-WAIT가 실제로 수행하는 작업과 더 중요한 것은 이것이 왜 중요한지에 대한 가장 명확한 예일 것입니다. 또한 TIME-WAIT를 '줄이기' 위해 Linux 시스템에 대한 일부 '전문가' 팁을 피해야 하는 이유도 설명합니다.

답변4

신뢰할 수 없는 프로토콜을 사용하면 피어 장치로부터 마지막 ​​메시지를 받았는지 확신할 수 없으므로 피어가 갑자기 전화를 끊었다고 가정하는 것은 위험합니다. 동시에 65000개 정도의 포트만 열 수 있다는 것은 TCP 프로토콜의 주요 단점입니다. 하지만 이를 극복하는 방법은 포트 번호를 빨리 재활용하는 것보다 로드에 따라 더 잘 확장되는 서버 팜으로 이동하는 것입니다. 클라이언트 측에서는 기본 워크스테이션인 경우 포트가 부족할 가능성이 거의 없습니다.

관련 정보