2009-05-22 4 views
12

저는 현재 일부 웹 서버 소프트웨어를 유지 관리하고 있으며 많은 I/O 작업을 수행해야합니다. read(), write(), close()shutdown() 호출은 소켓에서 사용될 때 ENOTCONN 오류가 발생할 수 있습니다. 이 오류는 정확히 무엇을 의미합니까? 그것을 유발할 수있는 조건은 무엇입니까? 로컬로 재현 할 수는 없지만 할 수있는 사용자가 있습니다.ENOTCONN 오류의 원인은 무엇입니까?

바로 지금은 close()shutdown()으로 발생했을 때 무시합니다. 무해한 것처럼 보이지만 완전히 확실하지 않습니다.

편집 :

  • 나는 connect() 호출이 성공했음을 절대적으로 확신합니다. 반환 값을 확인합니다.
  • ENOTCONN은 대부분 close()shutdown()으로 증가합니다. 나는 read()write()을 드물게 보았다. ENOTCONN.
+0

어떤 운영 체제입니까? 이전 Solaris 10 시스템에서 비슷한 문제를 추적하고 있습니다. 감사. – Nemo

+0

대부분 FreeBSD입니다.그 동안 유닉스 도메인 소켓을 다룰 때 close()와 shutdown()이 ENOTCONN을 반환하게하는 FreeBSD에 커널 버그가 있음을 알게되었습니다. Solaris에는 다양한 커널 버그 w.r.t가 있습니다. 유닉스 도메인 소켓, 비록 내가 connect()에서 버그를 관찰 해왔다. – Hongli

답변

13

TCP 연결의 측면에서 연결을 닫는 것이 없다고 확신하는 경우 원격 쪽에서 연결을 닫는 것처럼 나에게 들립니다.

ENOTCONN 다른 사람들이 지적한 것처럼 단순히 소켓이 연결되어 있지 않다는 의미입니다. 이것은 반드시 connect이 실패했음을 의미하지는 않습니다. 소켓이 이전에 잘 연결되었을 수 있습니다. 전화가 걸려 왔을 때 ENOTCONN이 아니 었습니다.

  • ECONNRESET :

    이것은 상이한 접속의 타단은 TCP 리셋 패킷을 전송. 다른 쪽 끝이 연결을 거부하거나 다른 쪽이 이미 연결되어 있다는 것을 인정하지 않으면 이런 일이 발생할 수 있습니다.

  • ETIMEDOUT : 일반적으로 connect에만 적용됩니다. 시스템에 종속 된 시간 내에 연결 시도가 성공하지 못한 경우에 발생할 수 있습니다. 때로는 일부 소켓 관련 시스템에 의해 반환 될 수

EPIPE 더 많거나 적은 ENOTCONN과 동일 조건에서 호출합니다.예를 들어, 일부 시스템에서는 EPIPEENOTCONNsend에 의해 반환 될 때 동의어입니다. 이 기능은 TCP 연결을 해체하도록되어 있기 때문에 shutdownENOTCONN을 반환하는 것은 드문 일이 아니다이지만

, 나는 close 반환 ENOTCONN을보고 놀랄 것입니다. 정말 그렇게해서는 안됩니다.

마지막으로 dwc가 언급 한대로 이미 close d 인 파일 설명자에 대해 일부 작업을 시도하지 않는 한 EBADF이 시나리오에 적용되지 않아야합니다. 소켓 연결 해제 (예 : TCP 연결 끊김)는 해당 소켓과 연결된 파일 설명자를 닫는 것과 동일하지 않습니다.

+0

틀렸어. 연결을 닫은 다른 쪽이 shutdown() 또는 close()가 실패하지 않는 이유입니다. 또한 shutdown()시 ENOTCONN은 실제로 RESET이 실제로 발생하지 않았 음을 나타냅니다. (자세한 내용은 내 대답을 참조하십시오.) –

+0

@ 로버트 : 내가 그렇게 말한 것 같지 않습니다. 나는 OPT가 관찰 했었다고 말했듯이'ENOTCONN'은'shutdown' (절대적으로 사실임)에 의해 반환 될 수 있고'close'에 의해 반환되지 않아야한다고 말한 것을 볼 수 있습니다 (또한 절대적으로 사실입니다) . –

+0

둘 다 말하지만 원격 측에서 ECONNRESET과 다른 연결을 닫았 기 때문에 ENOTCONN이 반환되었습니다. - ENOTCONN은 일반 원격으로 닫힌 연결을 위해 반환되지 않는다고 말합니다. 또한 shutdown() 구현은 ECONNRESET의 경우 ENOTCONN을 반환 할 수 있다고 생각합니다. 왜냐하면 shutdown()이 shutdown()에 의해 반환되지 않기 때문입니다. –

0

전송 종점 소켓 연결 지향 프로토콜과 연동하고, 연결되지 않은

연결되지 않는다. 이것은 대개 프로그래밍 결함입니다. 에서

: 당신이 확신하는 경우가 처음에 제대로 연결 한 http://www.wlug.org.nz/ENOTCONN

+1

오류의 이름은 알지만 그게 * 무엇을 의미합니까? 이 EPIPE, ECONNRESET 및 ETIMEDOUT과 다른 점은 무엇입니까? – Hongli

+0

connect()를 호출하지 않았거나 connect()가 성공했는지 확인하지 않았을 것입니다. –

+0

나는 성공했다. 이 문제를보고 한 사용자는 read() 및 write()가 정상적으로 작동하지만 shutdown() 및 close() 시간에 ENOTCONN을 발생시키는 것으로 나타났습니다. 로컬로 재생할 수 없으며 대부분의 사용자에게이 문제가 발생하지 않습니다. – Hongli

0

, ENOTCONN는 어느 fd에 의해 야기 될 가능성이 가장 높은 최종 휴관하는 동안 (다른 스레드에서 아마?) 당신은 요청의 중간에 있거나, 요청이 진행되는 동안 연결이 끊어짐에 따라.

어쨌든 소켓이 연결되어 있지 않다는 뜻입니다. 그 소켓을 청소하십시오. 죽었어. close() 또는 shutdown()을 호출해도 문제가 없습니다.

+0

나는 fd가 다른 스레드에 의해 닫히지 않는다고 확신한다. 그러나 EBADFD가 대신 발생하지 않을 것이라고 생각하십니까? 또한 read() 및 write()가 아닌 ENOTCONN을 발생시키는 것은 종종 close() 및 shutdown()입니다. 이것은 무엇을 의미할까요? – Hongli

+0

내 대답은 "요청 중간에"지정합니다. 그래서 당신은 전화를 걸고 실행은 다른 프로세스로 바뀝니다. 그런 다음 연결이 끊어지며 프로세스가 실행되기 시작합니다. EBADFD는 사실이 아니며 (유효한 fd입니다) 연결되어 있지 않습니다. 그래서 당신은 ENOTCONN을 얻습니다. – dwc

1

shutdown()이 ECONNRESET 또는 다른보다 정확한 오류를 반환하지 않기 때문에 ENOTCONN이 반환됩니다.

다른 쪽이 연결을 "막"한다고 가정하는 것은 잘못입니다. TCP 수준에서 다른 쪽은 연결을 절반 만 닫을 수 있습니다 (또는 중단합니다). 양측이 shutdown() (또는 close())을 수행하면 연결은 보통 완전히 닫힙니다. 양쪽면 모두 shutdown()이 실제로 성공합니다!

문제는 shutdown()이 이 아니고이 일반 (반쪽) 연결을 닫는 데 성공했거나 연결을 닫은 첫 번째 연결이 아니거나 두 번째 연결이 아니란 점입니다. - shutdown() (또는 요청을 처리하기위한 로컬 리소스 문제)에 전달 된 인수에 문제가 있음을 나타 내기 때문에 shutdown()에 대한 POSIX 문서에 나열된 오류에서 ENOTCONN이 가장 부적절합니다.

그래서 어떻게 된거 야? 요즘, 관련된 두 당사자 사이의 NAT 장치가 연결을 끊어서 반응으로 RESET 패킷을 보냈을 수 있습니다. 리셋 연결은 IPv4에서 매우 일반적이므로 코드에서 아무 곳에서나 얻을 수 있으며 shutdown()에서 ENOTCONN으로 마스크 처리됩니다.

코딩 버그가 원인 일 수 있습니다. 예를 들어, 비 블로킹 소켓에서 connect()는 성공적으로 연결되었음을 나타내지 않고 0을 반환 할 수 있습니다.

+0

FreeBSD 커널 버그로 이미 확인되었습니다. ENOTCONN 오류 코드는 Unix 도메인 소켓에서 관찰되었으므로 TCP는 아무 것도 할 수 없습니다. – Hongli

+0

이전에 연결된 TCP 소켓에서 작동하는 동안 ENOTCONN이 반환 된 이유를 찾는 중에 질문을 보았습니다. (당신의 경우는 아니지만 문제는 여전히 공중에 있습니다.) - 그 이유는 : 어딘가의 (커널) 버그이거나, ENOTCONN이라는 부적절한 라벨이 붙여진 연결의 오류 조건 때문입니다. 이유는 일반적인 원격 연결이 아니기 때문입니다. 그 대답은 유닉스 도메인 소켓 (당신의 경우)과 TCP 소켓 (나의 경우) 모두에 맞지 않습니다. –

1

소켓을 닫을 때() 소켓의 버퍼에있는 데이터가 수신자 소켓을 닫거나() 수신 한 소켓에 연결하여 대기중인 원격 파티에 전달되기를 기다리고 있기 때문입니다. 소켓 작동 방식에 대한 이해가 끝나지 않고 오히려 멍청한 의견입니다.이 "종료"기능이 구현 된 파일도 찾지 못했지만 전체 소켓 작업에 대한 사용자 설명서는 거의 없습니다. "통제 된"환경에서 오류가 발생할 때까지 모든 가능성을 시험하기 시작했습니다. 그것은 다른 것이 될 수 있지만, 많은 노력 후 이러한 내가가 정착 설명은 다음과 같습니다

  • 당신이 종료(), 오류를 얻을 때 원격 측이 연결을 종료 한 후 데이터를 전송합니다.
  • 원격 측에서 연결을 종료하기 전에 데이터를 전송했지만 다른 쪽에서 수신되지 않은 경우() 수신 한 경우() 한 번 shutdown() 할 수 있습니다. 다음에 shutdown()을 시도하면 오류가 발생합니다.
  • 데이터를 보내지 않았다면 원격 측이 shutdown()되지 않는 한 원하는 모든 시간을 종료 할 수 있습니다. 원격 측에서 shutdown()을 수행하면 shutdown()을 시도하고 소켓이 이미 shutdown() 된 경우 오류가 발생합니다.
관련 문제