답변:
이것은 Beej의 네트워킹 안내서에 설명 되어 있습니다. shutdown
한 방향 또는 두 방향으로 통신을 차단하는 유연한 방법입니다. 두 번째 매개 변수가 SHUT_RDWR
인 경우 (와 같은 close
) 전송 및 수신을 모두 차단합니다 . 하나,close
실제로 소켓을 파괴하는 방법입니다.
을 사용 shutdown
하면 피어가 이미 보낸 보류중인 데이터를 계속받을 수 있습니다 (이 점에 대해 Joey Adams에게 감사드립니다).
shutdown
양방향을 모두 사용하고 싶지만 한 가지 이유 는를 사용하여 소켓을 참조한 close
경우 입니다. 당신이 경우 소켓은, 새롭게 문을 연 파일은 같은 파일 디스크립터를 할당 할 수 있고, 후속 사용을 읽을 수는 / 아주 나쁜 될 수있는 잘못된 장소를 작성합니다. 방금의 경우 ,의 후속 사용 은 호출 될 때까지 오류를 발생시킵니다 . FILE
fdopen
close
FILE
shutdown
FILE
fclose
shutdown
EOF에게 피어에게 신호를 보내고 피어가 보낸 보류중인 데이터를 수신 할 수 있는 중요한 개념적 이유를 생략합니다 .
기존 답변 중 어느 것도 사람들에게 어떻게 shutdown
그리고 어떻게close
TCP 프로토콜 수준에서 작동 방식을 않으므로 추가해야합니다.
표준 TCP 연결은 4 방향 종료에 의해 종료됩니다.
그러나 TCP 연결을 닫는 또 다른 "비상"방법이 있습니다.
Wireshark를 사용한 테스트에서 기본 소켓 옵션 shutdown
을 사용하면 다른 쪽 끝으로 FIN 패킷을 보내지 만 그게 전부입니다. 상대방이 FIN 패킷을 보낼 때까지 데이터를 계속받을 수 있습니다. 이 일이 발생 Receive
하면 0 크기의 결과를 얻습니다. 따라서 "보내기"를 종료 한 첫 번째 사람이라면 데이터 수신을 마치면 소켓을 닫아야합니다.
반면에 전화하면 close
반면, 연결이 여전히 활성 상태 인 동안 (다른 쪽이 여전히 활성 상태이고 시스템 버퍼에 데이터를 보내지 하면 다른쪽으로 RST 패킷이 전송됩니다. 이것은 오류에 좋습니다. 예를 들어 상대방이 잘못된 데이터를 제공했거나 데이터 제공을 거부 한 경우 (DOS 공격?) 소켓을 즉시 닫을 수 있습니다.
규칙에 대한 나의 의견은 다음과 같습니다.
shutdown
하기 전에 close
가능하면SHUT_RD 및 SHUT_WR에 대한 이상적인 구현
다음은 테스트를 거치지 않았으므로 자신의 책임을 신뢰하십시오. 그러나 나는 이것이 합리적이고 실용적인 방법이라고 생각합니다.
TCP 스택이 SHUT_RD만으로 셧다운을 수신하면 더 이상 데이터가 예상되지 않는 것으로이 연결을 표시해야합니다. 그런 다음 보류중인 read
요청 과 후속 요청 (어느 스레드에 관계없이)은 크기가 0 인 결과로 반환됩니다. 그러나 연결은 여전히 활성 상태이며 사용 가능합니다. 예를 들어 여전히 OOB 데이터를 수신 할 수 있습니다. 또한 OS는이 연결에 대해 수신 한 모든 데이터를 삭제합니다. 그러나 그게 전부입니다. 패키지는 다른쪽으로 보내지지 않습니다.
TCP 스택이 SHUT_WR만으로 종료를 수신하면 더 이상 데이터를 전송할 수 없으므로이 연결을 표시해야합니다. 보류중인 모든 쓰기 요청은 완료되지만 후속 쓰기 요청은 실패합니다. 또한 FIN 패킷은 다른쪽으로 보내 져서 더 많은 데이터가 없다는 것을 알려줍니다.
shutdown()
연결을 한 후 더 이상 살아있다. 여전히 파일 디스크립터가 있습니다. recv()
수신 버퍼에서 여전히 가능 합니다. 그리고 close()
파일 디스크립터를 폐기 하려면 여전히 호출해야합니다 .
대신 close()
사용하면 피할 수있는 몇 가지 제한 사항 이 있습니다 shutdown()
.
close()
TCP 연결에서 양방향을 종료합니다. 때로는 다른 엔드 포인트에 데이터 전송이 완료되었지만 여전히 데이터를 수신하고 싶다고 말하려고합니다.
close()
디스크립터 참조 수 (파일 테이블 항목에서 유지 보수되고 파일 / 소켓을 참조하는 현재 열려있는 디스크립터 수를 카운트)를 줄이고 디스크립터가 0이 아닌 경우 소켓 / 파일을 닫지 않습니다. 이는 포크하는 경우, 정리는 참조 카운트가 0으로 떨어진 후에 만 발생합니다 shutdown()
. 참조 카운트를 무시하고 정상적인 TCP 닫기 시퀀스를 시작할 수 있습니다.
매개 변수는 다음과 같습니다.
int shutdown(int s, int how); // s is socket descriptor
int how
될 수 있습니다 :
SHUT_RD
또는 0
추가 수신이 허용되지 않습니다
SHUT_WR
또는 1
추가 전송이 허용되지 않습니다
SHUT_RDWR
또는 2
추가 발신 및 수신이 허용되지 않습니다
이것은 플랫폼에 따라 다를 수 있지만 어쨌든 의심 스럽지만 어쨌든 내가 본 가장 좋은 설명 은 종료, 느린 옵션, 소켓 클로저 및 일반적인 연결 종료 시퀀스에 대해 설명 하는이 msdn 페이지 입니다.
요약하면 shutdown을 사용하여 TCP 레벨에서 시스템 종료 시퀀스를 전송하고 close를 사용하여 프로세스의 소켓 데이터 구조에서 사용하는 자원을 확보하십시오. close를 호출 할 때까지 명시 적 종료 시퀀스를 발행하지 않은 경우 종료 시퀀스가 시작됩니다.
"shutdown ()은 실제로 파일 디스크립터를 닫는 것이 아니라 단지 그 유용성을 변경합니다. 소켓 디스크립터를 해제하려면 close ()를 사용해야합니다." 1
닫기
소켓 사용을 마치면 파일 설명자를 close로 닫을 수 있습니다. 연결을 통해 전송 대기중인 데이터가 여전히 있으면 일반적으로 닫기는이 전송을 완료하려고 시도합니다. SO_LINGER 소켓 옵션을 사용하여 시간 초과 기간을 지정하여이 동작을 제어 할 수 있습니다. 소켓 옵션을 참조하십시오.
일시 휴업
shutdown을 호출하여 연결에서 수신 또는 전송 만 종료 할 수도 있습니다.
종료 기능은 소켓 연결을 종료합니다. 수행 할 조치를 지정하는 방법 인수 : 0이 소켓에 대한 데이터 수신을 중지하십시오. 추가 데이터가 도착하면 거부하십시오. 1이 소켓에서 데이터 전송을 중지하십시오. 전송 대기중인 모든 데이터를 폐기하십시오. 이미 전송 된 데이터의 승인을 찾지 않습니다. 분실 한 경우에는 재전송하지 마십시오. 2 수신과 전송을 모두 중지하십시오.
성공하면 리턴 값은 0이고 실패하면 -1입니다.
내 시험에서.
close
소켓이 다른 프로세스와 공유되지 않으면 핀 패킷을 보내고 즉시 fd를 파괴합니다.
shutdown
SHUT_RD , 프로세스는 여전히 소켓에서 데이터를 가져올 수 있지만 recv
TCP 버퍼가 비어 있으면 0 recv
을 반환합니다. 피어가 더 많은 데이터 를 보낸 후 데이터를 다시 반환합니다.
shutdown
SHUT_WR 은 추가 전송이 허용되지 않음을 나타 내기 위해 핀 패킷을 전송합니다. 피어는 데이터를 수신 할 수 있지만 TCP 버퍼가 비어 있으면 0을 수신합니다.
shutdown
SHUT_RDWR피어가 더 많은 데이터를 보내면 ( SHUT_RD 와 SHUT_WR을 모두 사용함 )은 첫 번째 패킷을 보냅니다.
close()
FIN 대신 Linux에서 RST를 보냈습니다.
recv()
다시 데이터를 반환합니다'가 올바르지 않습니다. 2. 피어가 더 많은 데이터를 보낸 후의 동작 SHUT_RD
은 플랫폼에 따라 다릅니다.