[c] 소켓 대 종료?

C에서 소켓을 닫으면 소켓이 파괴되어 나중에 재사용 할 수 있음을 이해했습니다.

종료는 어떻습니까? 설명에 따르면 해당 소켓에 대한 이중 연결의 절반이 닫힙니다. 그러나 소켓이 close시스템 호출 처럼 파괴 됩니까?



답변

이것은 Beej의 네트워킹 안내서에 설명 되어 있습니다. shutdown한 방향 또는 두 방향으로 통신을 차단하는 유연한 방법입니다. 두 번째 매개 변수가 SHUT_RDWR인 경우 (와 같은 close) 전송 및 수신을 모두 차단합니다 . 하나,close 실제로 소켓을 파괴하는 방법입니다.

을 사용 shutdown하면 피어가 이미 보낸 보류중인 데이터를 계속받을 수 있습니다 (이 점에 대해 Joey Adams에게 감사드립니다).


답변

기존 답변 중 어느 것도 사람들에게 어떻게 shutdown그리고 어떻게close TCP 프로토콜 수준에서 작동 방식을 않으므로 추가해야합니다.

표준 TCP 연결은 4 방향 종료에 의해 종료됩니다.

  1. 참가자가 더 이상 전송할 데이터가 없으면 FIN 패킷을 상대방에게 보냅니다.
  2. 상대방이 FIN에 대한 ACK를 반환합니다.
  3. 상대방도 데이터 전송을 마치면 다른 FIN 패킷을 보냅니다.
  4. 초기 참가자는 ACK를 반환하고 전송을 마무리합니다.

그러나 TCP 연결을 닫는 또 다른 “비상”방법이 있습니다.

  1. 참가자는 RST 패킷을 보내고 연결을 포기합니다
  2. 다른 쪽은 RST를 수신 한 후 연결을 포기합니다.

Wireshark를 사용한 테스트에서 기본 소켓 옵션 shutdown을 사용하면 다른 쪽 끝으로 FIN 패킷을 보내지 만 그게 전부입니다. 상대방이 FIN 패킷을 보낼 때까지 데이터를 계속받을 수 있습니다. 이 일이 발생 Receive하면 0 크기의 결과를 얻습니다. 따라서 “보내기”를 종료 한 첫 번째 사람이라면 데이터 수신을 마치면 소켓을 닫아야합니다.

반면에 전화하면 close반면, 연결이 여전히 활성 상태 인 동안 (다른 쪽이 여전히 활성 상태이고 시스템 버퍼에 데이터를 보내지 하면 다른쪽으로 RST 패킷이 전송됩니다. 이것은 오류에 좋습니다. 예를 들어 상대방이 잘못된 데이터를 제공했거나 데이터 제공을 거부 한 경우 (DOS 공격?) 소켓을 즉시 닫을 수 있습니다.

규칙에 대한 나의 의견은 다음과 같습니다.

  1. 고려 shutdown하기 전에 close가능하면
  2. 종료하기로 결정하기 전에 (0 크기 데이터 수신) 수신을 완료 한 경우 마지막 송신 (있는 경우)이 끝난 후 연결을 닫으십시오.
  3. 연결을 정상적으로 닫으려면 연결을 종료하고 (SHUT_WR을 사용하고이 시점 이후에 SHUT_RD를 사용하여 데이터 수신에 신경 쓰지 않는 경우) 0 크기의 데이터가 수신 될 때까지 기다렸다가 소켓.
  4. 어쨌든 다른 오류가 발생한 경우 (예 : 시간 초과) 소켓을 닫으면됩니다.

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입니다.