2008-10-02 5 views
11

수신 대기 (fd, 백 로그)를 호출 한 후 소켓에서 수신을 취소 할 수 있습니까?소켓에서 비표 시할 수 있습니까?

편집 : 자신을 분명히하지 않는 실수. 내가 일시적으로 소켓에 unlisten 수 싶습니다. close()를 호출하면 소켓이 M2LS 상태가되어 다시 열지 못하게됩니다 (또는 악의적 인 프로그램이 소켓에 바인딩 될 수 있음)

일시적으로 신호를받지 않는 방법이 신호를 보내는 방법이 될 수 있습니다 이 응용 프로그램이 더 이상 요청을 수락 할 수없는 업스트림 부하 분산 장치에

답변

3

일부 소켓 라이브러리를 사용하면 들어오는 연결을 명확하게 거부 할 수 있습니다. 예 : GNU's CommonC++: TCPsocket Class의 경우 reject 메소드가 있습니다.

BSD 소켓에는이 기능이 없습니다. 당신은 수도

...

while (running) { 

    int i32ConnectFD = accept(i32SocketFD, NULL, NULL); 
    while (noConnectionsPlease) { 
    shutdown(i32ConnectFD, 2); 
    close(i32ConnectFD); 
    break; 
    } 

} 
+0

) 프로토콜 레벨에서 동일한 효과를 내지 않는데, 수신 대기 로그가 가득 차서 연결을 거부하거나 연결을 거부하면 Dave가 원하는 것을 달성하지 못할 수도 있습니다 로드 밸런서 등등. 이것은 단지 짧은 만료 된 성공적인 연결처럼 보일 것입니다. –

+0

BSD 소켓을 사용하면 소켓을 잃지 않고 언로드 할 방법이 없으므로 완벽한 방법은 아닙니다. accept를 가진 커넥션에 대한 소켓 핸들을 먼저 얻지 않고 close를 수행한다. 이것이 작동하지 않는다면 Dave는 새로운 소켓 라이브러리가 필요하다. –

+0

당신의 대답에있는 링크가 깨진다. –

4

닫습니다. 내가 상기 한 것처럼.

close(fd); 
1

명시 적으로 지정 해제 할 방법이 없습니다.

중 하나를 수행 할 수 있습니다 일부 weirdiness의 내가 정확히에 대해 모르기 때문에 close(fd) 또는

fd is the socket file descriptor you want to shutdown, and how is one of the following: 

0 Further receives are disallowed 

1 Further sends are disallowed 

2 Further sends and receives are disallowed (like close()) 
+0

shutdown()이 허용 될 수 있지만, 어떤 효과가있을 것으로 예상되는 유일한 값은 0 또는 2로, 어쨌든 청취 소켓의 모든 유용성을 종료합니다. close()가 더 쉽고, 특히 (내가 추측하고있다) C에서 명확하다. –

5

shutdown(fd, how) 소켓을 닫은 후, 프로그램은 여전히 ​​소켓이 "사용"이라고 말할 수 있습니다,이입니다 . 그러나 소켓에 관한 맨 페이지는 "SO_REUSEADDR"라고 불리는 같은 소켓을 재사용 할 수있는 플래그가 있음을 보여줍니다. "setsockopt()"를 사용하여 설정하십시오.

+1

잘 모르겠지만 setsockopt()를 통해 SO_LINGER 옵션을 끄면 도움이 될 것이다. – Ferruccio

0

소켓은 기본적으로 열려 있거나 닫혀 있습니다 (여기서 TCP/IP 상태 다이어그램을 무시합니다).

소켓이 닫혀 있으면 아무 것도 데이터를 보낼 수 없습니다. 열려 있으면 TCP/IP 스택에 의해 들어오는 데이터가 받아 들여지고 받아 들여질 것입니다. 버퍼링 알고리즘이 "충분히!" 이 시점에서 추가 데이터는 인정되지 않습니다.

내가 볼 수있는 두 가지 선택 사항이 있습니다. "unlisten"을 원할 때 소켓을 닫은 다음 나중에 다시 엽니 다. SO_REUSEADDR 플래그와 setsockopt()를 사용하여 TIME_WAIT2가 만료되기 전에 잘 알려진 포트로 리 바인드 할 수 있습니다.

다른 옵션은 소켓을 열어 두지 만 '사용 중'일 때는 accept()하지 않는 것입니다. 요청에 대한 응용 프로그램 수준의 확인이 있다고 가정하면 부하 분산 장치는 응답을받지 못하고 그에 따라 작동한다는 것을 알게됩니다.

2

편집 한 버전의 질문을 토대로 "비인가"또는 닫기()가 확실하지 않습니다. 두 가지 옵션이 있습니다 :

1) listen()을 호출 한 후 accept()를 호출 할 때까지 (논리적으로 충분히) 연결이 실제로 허용되지 않습니다. 소켓 작업을 무시하고 accept()를 연기 할 때까지 "unlisten"할 수 있습니다. 모든 인바운드 연결은 포트가 수신 대기 모드로 열렸을 때 작성된 대기열에 백 로그를 시도합니다. 백 로그 대기열이 스택에서 가득차면 추가 연결 시도가 단순히 바닥에 떨어집니다. accepts()를 사용하여 재개하면 신속하게 백 로그를 대기열에서 제외하고 더 많은 연결을 준비 할 수 있습니다.

2) 포트가 일시적으로 완전히 닫히지 않게하려면 커널 수준의 패킷 필터를 포트에 동적으로 적용하여 인바운드 연결 시도가 네트워크 스택에 도달하지 못하게 할 수 있습니다. 예를 들어, 대부분의 * nix 플랫폼에서 BPF (Berkeley Packet Filter)를 사용할 수 있습니다. 즉, 플랫폼의 방화벽 기능을 사용하여 관심있는 포트로 들어오는 인바운드 패킷을 드롭하려고합니다. 이것은 물론 플랫폼에 따라 다르지만 가능한 접근 방법입니다.보통의 백 로그 청취

열기 소켓 :

+0

accept() 백 로그에 이러한 연결을 유지하는 데 문제가 있습니다. accept()하지 않았더라도 업스트림 LB는 현재 대기열 (요청을 처리하지 않음)을 알 수 없습니다. 한 가지 아이디어는 백 로그를 1로 설정하면 대기열에있는 요청이있는 경우 이후의 요청은 계속 실패하고 –

+0

(메모가 300 자로 제한되는 이유는 무엇입니까?) 계속해서 내 서버에 책임을 다시두고 accept() 백 로그를 정기적으로 지우지 만 그 어쨌든 이상적인 조건에서 일어날 일이고, 이상적인 조건 하에서 LB가 E_CONNREFUSED를 얻는 것은 대기열 단점을 피할 것입니다. –

+0

@Dave'accept()'를 연기하는 또 다른 문제는 select 나 level-triggered epoll : 청취 소켓에서 지속적으로 활동을보고합니다. 일시적으로 청취 소켓의 FD를 시계 세트에서 제거 할 수 있다고 가정합니다. 그러나 내 응용 프로그램에서는 일부 추상화를 통해 깨뜨릴 수 있습니다. ( –

0

여기에 편집 된 질문에 따라 다소 추한 방법입니다. 발하다.

"종료"할 때 백 로그 1 및 SO_REUSEADDR로 두 번째 것을 엽니 다. 첫 번째 것을 닫으십시오. 재개 할 준비가되면 정상적인 백 로그가있는 소켓 저글링을 수행하십시오.

닫는 소켓에서 수락 큐를 비우는 것과 관련된 세부 사항은 여기에 있습니다. 아마이 접근법을 생존시키기에 충분할만큼 살인자 일 겁니다.

0

내가 반드시이 좋은 아이디어라고 생각하지 않지만, : 당신은 열린 소켓을 유지하면서,에게 가까이에게 그것을 다음 연결 즉시 을 받아 들일 수 두 번 청취 할 수 있어야합니다. POSIX 사양은 그렇지 않다고 말하지 않습니다. 아마 당신은 당신이 "unlisten"하고 싶을 때 백 로그 파라미터 0으로 두 번째 호출 할 수 있습니다.

백 로그가 0 인 상태에서 수신 대기가 발생하면 구현 정의 된 것처럼 보입니다. POSIX 사양에서는 일 수 있습니다.은 연결 허용을 허용합니다. 이는 백 로그 매개 변수가 0 인 경우 일부 구현에서 모든 연결을 거부하도록 선택할 수 있음을 의미합니다. 0을 전달할 때 구현에서 양수 값을 선택합니다. 1 또는 SOMAXCONN).

2

업스트림로드 밸런서에게 신호를 보내는 것이 좋다고 생각하지 않습니다. 실제로 메시지가 전달되기 전에 서버에 연결을 보내야합니다. 연결이 거부 될 수 있습니다.

마찬가지로 수신 대기 소켓을 닫을 때 보류중인 모든 연결은 데이터없이 닫힙니다.

업스트림 부하 분산 장치에 신호를 보내려면이를 수행하기위한 프로토콜이 있어야합니다. TCP를 악용하려고 시도하지 마십시오.

다행히도 클라이언트가 일반 웹 브라우저 인 경우 대단히 많이 벗어날 수 있습니다. 단순히 소켓을 닫으면 일반적으로 사용자가 (지점까지) 투명하게 다시 시도합니다.

0

질문은 어떤 종류의 소켓을 말하지 않았다. 유닉스 소켓이라면, rename (2)를 멈추고 듣기 시작할 수있다. unlink (2)를 사용하여 청취를 영구적으로 중단 할 수 있으며, 소켓이 열린 채로 있기 때문에 백 로그 서비스를 계속할 수 있습니다. 이 접근법은 전에는 사용하지 않고 직접 탐색하는 것이기는하지만 매우 편리합니다.

0

소켓 API를 통해이 작업을 수행 할 수 없다는 답변이 이미 있습니다.

다른 OS 방법 (예 : 호스트 전체/iptables/ipfilter)을 사용하여 임시 거부 규칙을 설정할 수 있습니다.

나는 대부분의로드 밸런서들이 (대부분이 아닌 합법적 인 연결 시도에 대한 응답으로 만 연결 프로브에 RST를 인식하고 있습니다.)

연결 문제를 인식하기 위해 제공하는 가능성에 제한 약간 것으로 나타났습니다 어쨌든, 당신이 inavailability를 탐지하는 probe에 의해 제한된다면, HTTP 요청이나 FTP 로그인을하는 application level probe를 설정하거나 accept 후에 그냥 닫으면 인식할만한 것들을 설정합니다. 어쨌든 나에게 깨끗해 보이는 "500 service not available"과 같은 오류 메시지를 해석 할 수도 있습니다. SNMP를 사용하면 일부로드 밸런서는 결과를로드 힌트로 사용할 수도 있습니다.

관련 문제