SO_REUSEADDR (setsockopt 옵션)-Linux의 의미는 무엇입니까?
이 질문에 이미 답변이 있습니다.
man 페이지에서 :
SO_REUSEADDR 프로토콜에서 지원하는 경우 bind ()에 제공된 주소 유효성 검사에 사용되는 규칙이 로컬 주소의 재사용을 허용해야 함을 지정합니다. 이 옵션은 int 값을 사용합니다. 이것은 부울 옵션입니다.
언제 사용해야합니까? "로컬 주소 재사용"이 제공되는 이유는 무엇입니까?
TCP의 기본 설계 목표는 패킷 손실, 패킷 재정렬 및 여기서 핵심적인 패킷 복제에 직면하여 안정적인 데이터 통신을 허용하는 것입니다.
연결이 설정되어있는 동안 TCP / IP 네트워크 스택이이 모든 것을 처리하는 방법은 매우 분명하지만 연결이 종료 된 직후에 발생하는 경계 케이스가 있습니다. 대화의 끝에서 바로 전송 된 패킷이 복제되고 지연 되어 4 방향 종료 패킷이 지연된 패킷보다 먼저 수신자에게 전달되면 어떻게됩니까? 스택은 성실하게 연결을 종료합니다. 그런 다음 나중에 지연된 중복 패킷이 나타납니다. 스택은 무엇을해야합니까?
더 중요한 것은 주어진 IP 주소 + TCP 포트 콤보에 열린 소켓이있는 프로그램이 소켓을 닫은 다음 잠시 후 프로그램이 나타나서 동일한 IP 주소와 TCP 포트 번호를 수신하려는 경우 어떻게해야합니까? ? (일반적인 경우 : 프로그램이 종료되고 빠르게 다시 시작됩니다.)
몇 가지 선택 사항이 있습니다.
패킷이 전송 될 수있는 최대 시간의 최소 2 배 동안 해당 IP / 포트 콤보의 재사용을 허용하지 않습니다. TCP에서는 일반적으로 2x MSL 지연 이라고합니다 . 때로는 대략적으로 동일한 2 × RTT 도 표시 됩니다.
이것은 모든 공통 TCP / IP 스택의 기본 동작입니다. 2 × MSL은 일반적으로 30 초에서 120 초 사이이며
netstat
출력에TIME_WAIT
주기로 표시됩니다. 그 시간이 지나면 스택은 만료 된 TTL 로 인해 경로 에서 불량 패킷이 삭제되었다고 가정하여 소켓이 상태를 벗어나 해당 IP / 포트 콤보를 재사용 할 수 있습니다.TIME_WAIT
새 프로그램이 해당 IP / 포트 콤보에 다시 바인딩되도록합니다. BSD 소켓 인터페이스가있는 스택 ( 기본적으로 모든 Unix 및 Unix 계열 시스템과 Winsock을 통한 Windows) 에서는를 호출하기 전에
SO_REUSEADDR
옵션을 설정하여이 동작을 요청setsockopt()
해야합니다bind()
.
SO_REUSEADDR
일반적인 사용 패턴은 구성을 변경하는 것이기 때문에 네트워크 서버 프로그램에서 가장 일반적으로 설정되며 변경 사항을 적용하려면 해당 프로그램을 다시 시작해야합니다. 없이 SO_REUSEADDR
1, bind()
재시작 된 프로그램의 새 인스턴스의 호출 당신이 그것을 죽였을 때 연결이 이전의 인스턴스에 열이 있다면 실패합니다. 이러한 연결은 TCP 포트 TIME_WAIT
를 30-120 초 동안 유지하므로 위의 경우 1에 해당합니다.
설정의 위험 SO_REUSEADDR
은 모호함을 생성한다는 것입니다. TCP 패킷 헤더의 메타 데이터는 스택이 패킷이 오래되었는지 여부를 안정적으로 알 수있을만큼 충분히 고유하지 않으므로 새 리스너의 소켓으로 전달되는 대신 삭제해야합니다. 이제 죽은 청취자를위한 것이 분명합니다.
이것이 사실이라는 것을 알지 못한다면, 다음은 그 결정을 내리기 위해 연결 당 작업해야하는 모든 청취 머신의 TCP / IP 스택입니다.
로컬 IP : 콘당 고유하지 않습니다. 사실, 여기서 우리의 문제 정의는 의도적으로 로컬 IP를 재사용하고 있다고 말합니다.
로컬 TCP 포트 : Ditto.
원격 IP : 모호성을 유발하는 시스템이 다시 연결될 수 있으므로 패킷의 적절한 대상을 명확하게하는 데 도움이되지 않습니다.
원격 포트 : 잘 작동하는 네트워크 스택에서 나가는 연결의 원격 포트는 빠르게 재사용되지 않지만 16 비트에 불과하므로 스택이 수만 개를 통과하도록 강제하는 데 30-120 초가 걸립니다. 선택하고 포트를 재사용하십시오. 1960 년대에는 컴퓨터가 그렇게 빠르게 작동 할 수있었습니다.
이에 대한 대답이 원격 스택이 일시적인 TCP 포트 재사용
TIME_WAIT
을 허용하지 않기 위해 같은 작업을 수행해야한다는 것이라면 해당 솔루션은 원격 호스트가 무해한 것으로 가정합니다. 악의적 인 행위자는 해당 원격 포트를 자유롭게 재사용 할 수 있습니다.리스너의 스택이 TCP 4- 튜플의 연결 만 엄격하게 허용하지 않도록 선택할 수 있다고 가정합니다. 따라서 해당
TIME_WAIT
상태에서 특정 원격 호스트가 동일한 원격 임시 포트로 다시 연결되지 않도록 할 수 있지만 TCP 스택은 다음과 같습니다. 그 특별한 개선.로컬 및 원격 TCP 시퀀스 번호 : 또한 새 원격 프로그램이 동일한 값을 얻을 수 없을만큼 충분히 고유하지 않습니다.
오늘 TCP를 재 설계했다면 TLS 또는 이와 유사한 것을 비 선택적 기능으로 통합 할 것이라고 생각 합니다. 그 중 하나의 효과는 이러한 종류의 부주의하고 악의적 인 연결 하이재킹을 불가능하게 만드는 것이지만이를 위해서는 큰 필드를 추가해야합니다. (128 비트 이상) TCP의 현재 버전 ( RFC 793 )에 대한 문서 가 게시 된 1981 년에는 전혀 실용적이지 않았습니다 .
이러한 강화 없이는 리 바인딩을 허용하여 생성 된 모호함으로 인해 TIME_WAIT
a) 이전 리스너를위한 오래된 데이터가 새 리스너에 속한 소켓으로 잘못 전달되어 리스너의 프로토콜이 깨지거나 오래된 데이터를 잘못 주입 할 수 있습니다. 연결; 또는 b) 새 리스너의 소켓에 대한 새 데이터가 이전 리스너의 소켓에 잘못 할당되어 실수로 삭제되었습니다.
안전한 방법은 TIME_WAIT
기간을 기다리는 것 입니다.
궁극적으로 비용 선택에 달려 있습니다. TIME_WAIT
기간을 기다리 거나 원치 않는 데이터 손실 또는 의도하지 않은 데이터 주입의 위험을 감수하십시오.
Many server programs take this risk, deciding that it's better to get the server back up immediately so as to not miss any more incoming connections than necessary.
This is not a universal choice. Many programs — even server programs requiring a restart to apply a settings change — choose instead to leave SO_REUSEADDR
alone. The programmer may know these risks and is choosing to leave the default alone, or they may be ignorant of the issues but are getting the benefit of a wise default.
Some network programs offer the user a choice among the configuration options, fobbing the responsibility off on the end user or sysadmin.
SO_REUSEADDR allows your server to bind to an address which is in a
TIME_WAIT state.
This socket option tells the kernel that even if this port is busy (in the TIME_WAIT state), go ahead and reuse it anyway. If it is busy, but with another state, you will still get an address already in use error. It is useful if your server has been shut down, and then restarted right away while sockets are still active on its port.
From unixguide.net
When you create a socket, you don't really own it. The OS (TCP stack) creates it for you and gives you a handle (file descriptor) to access it. When your socket is closed, it take time for the OS to "fully close it" while it goes through several states. As EJP mentioned in the comments, the longest delay is usually from the TIME_WAIT state. This extra delay is required to handle edge cases at the very end of the termination sequence and make sure the last termination acknowledgement either got through or had the other side reset itself because of a timeout. Here you can find some extra considerations about this state. The main considerations are pointed out as follow :
Remember that TCP guarantees all data transmitted will be delivered, if at all possible. When you close a socket, the server goes into a TIME_WAIT state, just to be really really sure that all the data has gone through. When a socket is closed, both sides agree by sending messages to each other that they will send no more data. This, it seemed to me was good enough, and after the handshaking is done, the socket should be closed. The problem is two-fold. First, there is no way to be sure that the last ack was communicated successfully. Second, there may be "wandering duplicates" left on the net that must be dealt with if they are delivered.
If you try to create multiple sockets with the same ip:port pair really quick, you get the "address already in use" error because the earlier socket will not have been fully released. Using SO_REUSEADDR will get rid of this error as it will override checks for any previous instance.
'program tip' 카테고리의 다른 글
Laravel이 블레이드 템플릿의 모든 HTML을 이스케이프 (0) | 2020.12.14 |
---|---|
누락 된 문자가있는 단어를 찾기위한 좋은 알고리즘 및 데이터 구조? (0) | 2020.12.14 |
JavaScript에서 새로 추가 된 요소에 onclick 이벤트 추가 (0) | 2020.12.14 |
jQuery, .each를 사용하여 클래스의 각 요소 ID를 얻습니까? (0) | 2020.12.14 |
JPA 엔티티에 equals () 및 hashCode () 메소드를 작성해야합니까? (0) | 2020.12.14 |