socket.shutdown 대 socket.close


122

나는 최근에 다음과 같은 약간의 코드를 보았습니다 (물론 소켓은 소켓 객체입니다) :

sock.shutdown(socket.SHUT_RDWR)
sock.close()

소켓에서 종료를 호출 한 다음 닫는 목적은 정확히 무엇입니까? 차이가 나는 경우이 소켓은 비 차단 IO에 사용됩니다.

답변:


38

다음은 한 가지 설명입니다 .

소켓이 더 이상 필요하지 않으면 호출 프로그램은 소켓 설명자에 닫기 서브 루틴을 적용하여 소켓을 버릴 수 있습니다. 신뢰할 수있는 배달 소켓에 닫기가 발생할 때 연결된 데이터가 있으면 시스템은 데이터 전송을 계속 시도합니다. 그러나 데이터가 여전히 전달되지 않으면 시스템은 데이터를 버립니다. 응용 프로그램이 보류중인 데이터를 사용하지 않는 경우 소켓을 닫기 전에 종료 서브 루틴을 사용할 수 있습니다.


241

호출 close하고 shutdown기본 소켓에 두 가지 다른 효과가 있습니다.

가장 먼저 지적해야 할 점은 소켓이 기본 OS의 리소스이고 여러 프로세스가 동일한 기본 소켓에 대한 핸들을 가질 수 있다는 것입니다.

호출 close하면 핸들 수가 1 씩 감소하고 핸들 수가 0에 도달하면 소켓과 관련 연결이 정상적인 닫기 절차를 거치고 (효과적으로 FIN / EOF를 피어에 전송) 소켓이 할당 해제됩니다.

여기서주의해야 할 점은 다른 프로세스가 여전히 소켓에 대한 핸들을 가지고 있기 때문에 핸들 수가 0에 도달하지 않으면 연결 이 닫히지 않고 소켓이 할당 해제되지 않는다는 것입니다.

반면 shutdown에 읽기 및 쓰기를 호출 하면 기본 연결이 닫히고 소켓에 대한 핸들이있는 프로세스 수에 관계없이 피어에게 FIN / EOF를 보냅니다. 그러나 소켓 할당을 해제 하지 않으므로 나중에 close를 호출해야합니다.


멋진 대답, 내가 무엇을 찾아 방해하지 shutdown(): 않습니다
매트 소목에게

2
읽기를위한 shutdown ()으로 인해 FIN 패킷을 보낼 수 있습니까? 즉, shutdown (sock_fd, 1);
ernesto 2014

항상 .shutdown()다음 전화로 전화하는 것이 현명 .close()할까요? 아니면 그 사이에 지연이 있어야합니까?
Luc

@Luc 당신이하는 일에 완전히 의존합니다.
Robert S. Barnes

2
@Luc 그런 다음 다른 프로세스가 소켓에 대한 핸들을 가지고 있지 않는 한 닫는 것이 좋습니다.
Robert S. Barnes

17

종료 및 닫기에 대한 설명 : 정상 종료 (msdn)

종료 (귀하의 경우)는 연결의 다른 쪽 끝에 소켓에서 읽거나 쓸 의도가 없음을 나타냅니다. 그런 다음 close는 소켓과 관련된 모든 메모리를 해제합니다.

종료를 생략하면 연결이 정상적으로 닫힐 때까지 소켓이 OS 스택에 남아있을 수 있습니다.

IMO는 'shutdown'과 'close'라는 이름은 오해의 소지가 있으며 'close'와 'destroy'는 차이점을 강조합니다.


다른 쪽 끝에 더 이상 읽을 의도가 없음을 나타내지는 않습니다. 읽기를위한 종료는 피어에 아무것도 보내지 않습니다.
Marquis of Lorne

7

소켓 프로그래밍 하우투 ( py2 / py3 )에 바로 언급되어 있습니다.

연결 해제

엄밀히 말하면, shutdown소켓을 먼저 사용해야 close합니다. 은 shutdown다른 쪽 끝에서 소켓에 대한 자문이다. 전달한 인수에 따라 " 더 이상 보내지 않겠습니다.하지만 여전히 듣겠습니다. "또는 " 잘 듣지 않습니다. ”. 그러나 대부분의 소켓 라이브러리는 일반적으로 a close와 동일 하므로이 에티켓을 사용하지 않는 프로그래머에게 너무 익숙합니다 shutdown(); close(). 따라서 대부분의 상황에서 명시적인 종료가 필요하지 않습니다.

...


이 정보는 정확하지 않습니다. (1) 프로세스를 포크하고 지금 FIN을 확실히 보내고 자하는 경우 또는 (2) 두 피어가 닫히도록 상호 EOS 읽기 프로토콜에 참여하는 경우에만 쓰기를 위해 소켓을 종료해야합니다. 동시에. 그렇지 않으면 close()충분합니다. Python 문서를 수정해야합니다.
Marquis of Lorne

4

위의 코드가 틀리지 않나요?

종료 호출 직후의 close 호출은 어쨌든 커널이 나가는 모든 버퍼를 버리도록 만들 수 있습니다.

http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable 에 따르면 종료와 읽기가 0을 반환 할 때까지 닫습니다.


정확하지 않습니다. 커널은 연결이 재설정 된 경우에만 나가는 버퍼를 삭제합니다. 이는 로컬 앱이 이미 도착한 보류중인 모든 인바운드 데이터를 읽지 않았거나 피어가 SO_LINGER를 엉망으로 만든 경우 발생할 수 있습니다. . 잠을 자거나 닫기 전에 종료를 호출 할 필요도 없습니다. 이 문제에 대해 잘못된 정보가 많이 있습니다.
Marquis of Lorne


1

Shutdown (1), 소켓 no가 더 이상 데이터를 보내도록합니다.

이것은 유용합니다

1- 버퍼 플러싱

2- 이상한 오류 감지

3- 안전 가드

좀 더 설명하겠습니다. A에서 B로 데이터를 보낼 때 B로 전송되는 것은 보장되지 않으며 A os 버퍼로만 전송되고 B os 버퍼로 전송됩니다.

따라서 A에서 shutdown (1)을 호출하면 A의 버퍼를 플러시하고 버퍼가 비어 있지 않으면 오류가 발생합니다. 즉, 데이터가 아직 피어에 전송되지 않았습니다.

그러나 이것은 돌이킬 수 없으므로 모든 데이터를 완전히 보낸 후에 할 수 있으며 피어 os 버퍼에서 최소한인지 확인하고 싶습니다.


종료는 강제로 플러시하지 않습니다. 버퍼링 상황은 변경되지 않습니다. 버퍼가 비어 있지 않으면 오류가 발생하지 않습니다. FIN은 보류중인 데이터 뒤에 대기열에 추가됩니다. 답이 완전히 틀 렸습니다.
Marquis of Lorne
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.