C에서 소켓을 닫으면 소켓이 파괴되어 나중에 재사용 할 수 있음을 이해했습니다.
종료는 어떻습니까? 설명에 따르면 해당 소켓에 대한 이중 연결의 절반이 닫힙니다. 그러나 소켓이 close
시스템 호출 처럼 파괴 됩니까?
답변
이것은 Beej의 네트워킹 안내서에 설명 되어 있습니다. shutdown
한 방향 또는 두 방향으로 통신을 차단하는 유연한 방법입니다. 두 번째 매개 변수가 SHUT_RDWR
인 경우 (와 같은 close
) 전송 및 수신을 모두 차단합니다 . 하나,close
실제로 소켓을 파괴하는 방법입니다.
을 사용 shutdown
하면 피어가 이미 보낸 보류중인 데이터를 계속받을 수 있습니다 (이 점에 대해 Joey Adams에게 감사드립니다).
답변
기존 답변 중 어느 것도 사람들에게 어떻게 shutdown
그리고 어떻게close
TCP 프로토콜 수준에서 작동 방식을 않으므로 추가해야합니다.
표준 TCP 연결은 4 방향 종료에 의해 종료됩니다.
- 참가자가 더 이상 전송할 데이터가 없으면 FIN 패킷을 상대방에게 보냅니다.
- 상대방이 FIN에 대한 ACK를 반환합니다.
- 상대방도 데이터 전송을 마치면 다른 FIN 패킷을 보냅니다.
- 초기 참가자는 ACK를 반환하고 전송을 마무리합니다.
그러나 TCP 연결을 닫는 또 다른 “비상”방법이 있습니다.
- 참가자는 RST 패킷을 보내고 연결을 포기합니다
- 다른 쪽은 RST를 수신 한 후 연결을 포기합니다.
Wireshark를 사용한 테스트에서 기본 소켓 옵션 shutdown
을 사용하면 다른 쪽 끝으로 FIN 패킷을 보내지 만 그게 전부입니다. 상대방이 FIN 패킷을 보낼 때까지 데이터를 계속받을 수 있습니다. 이 일이 발생 Receive
하면 0 크기의 결과를 얻습니다. 따라서 “보내기”를 종료 한 첫 번째 사람이라면 데이터 수신을 마치면 소켓을 닫아야합니다.
반면에 전화하면 close
반면, 연결이 여전히 활성 상태 인 동안 (다른 쪽이 여전히 활성 상태이고 시스템 버퍼에 데이터를 보내지 하면 다른쪽으로 RST 패킷이 전송됩니다. 이것은 오류에 좋습니다. 예를 들어 상대방이 잘못된 데이터를 제공했거나 데이터 제공을 거부 한 경우 (DOS 공격?) 소켓을 즉시 닫을 수 있습니다.
규칙에 대한 나의 의견은 다음과 같습니다.
- 고려
shutdown
하기 전에close
가능하면 - 종료하기로 결정하기 전에 (0 크기 데이터 수신) 수신을 완료 한 경우 마지막 송신 (있는 경우)이 끝난 후 연결을 닫으십시오.
- 연결을 정상적으로 닫으려면 연결을 종료하고 (SHUT_WR을 사용하고이 시점 이후에 SHUT_RD를 사용하여 데이터 수신에 신경 쓰지 않는 경우) 0 크기의 데이터가 수신 될 때까지 기다렸다가 소켓.
- 어쨌든 다른 오류가 발생한 경우 (예 : 시간 초과) 소켓을 닫으면됩니다.
SHUT_RD 및 SHUT_WR에 대한 이상적인 구현
다음은 테스트를 거치지 않았으므로 자신의 책임을 신뢰하십시오. 그러나 나는 이것이 합리적이고 실용적인 방법이라고 생각합니다.
TCP 스택이 SHUT_RD만으로 셧다운을 수신하면 더 이상 데이터가 예상되지 않는 것으로이 연결을 표시해야합니다. 그런 다음 보류중인 read
요청 과 후속 요청 (어느 스레드에 관계없이)은 크기가 0 인 결과로 반환됩니다. 그러나 연결은 여전히 활성 상태이며 사용 가능합니다. 예를 들어 여전히 OOB 데이터를 수신 할 수 있습니다. 또한 OS는이 연결에 대해 수신 한 모든 데이터를 삭제합니다. 그러나 그게 전부입니다. 패키지는 다른쪽으로 보내지지 않습니다.
TCP 스택이 SHUT_WR만으로 종료를 수신하면 더 이상 데이터를 전송할 수 없으므로이 연결을 표시해야합니다. 보류중인 모든 쓰기 요청은 완료되지만 후속 쓰기 요청은 실패합니다. 또한 FIN 패킷은 다른쪽으로 보내 져서 더 많은 데이터가 없다는 것을 알려줍니다.
답변
대신 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()
에서 한 pthread를 사용 하여 다른 pthread를 강제로 차단 하여 성공 했습니다.connect()
일찍 중단 .
다른 OS (최소한 OSX)에서는 호출 close()
이 connect()
실패 하기에 충분 하다는 것을 알았습니다 .
답변
“shutdown ()은 실제로 파일 디스크립터를 닫는 것이 아니라 단지 그 유용성을 변경합니다. 소켓 디스크립터를 해제하려면 close ()를 사용해야합니다.” 1
답변
닫기
소켓 사용을 마치면 파일 설명자를 close로 닫을 수 있습니다. 연결을 통해 전송 대기중인 데이터가 여전히 있으면 일반적으로 닫기는이 전송을 완료하려고 시도합니다. SO_LINGER 소켓 옵션을 사용하여 시간 초과 기간을 지정하여이 동작을 제어 할 수 있습니다. 소켓 옵션을 참조하십시오.
일시 휴업
shutdown을 호출하여 연결에서 수신 또는 전송 만 종료 할 수도 있습니다.
종료 기능은 소켓 연결을 종료합니다. 수행 할 조치를 지정하는 방법 인수 : 0이 소켓에 대한 데이터 수신을 중지하십시오. 추가 데이터가 도착하면 거부하십시오. 1이 소켓에서 데이터 전송을 중지하십시오. 전송 대기중인 모든 데이터를 폐기하십시오. 이미 전송 된 데이터의 승인을 찾지 않습니다. 분실 한 경우에는 재전송하지 마십시오. 2 수신과 전송을 모두 중지하십시오.
성공하면 리턴 값은 0이고 실패하면 -1입니다.