2012-01-15 3 views
23

send() 직후에 close() 소켓에 현명한/안전합니까?send() : close() 안전하지 않은 close() 소켓?

나는 TCP가 소켓을 닫은 후에도 송신 버퍼에 남아있는 모든 데이터를 전달하려고 시도한다는 것을 알고 있지만 실제로 그렇게 할 수 있습니까?

수신 버퍼에 남아있는 데이터가 없으므로 폐쇄 후 RST가 전송되지 않도록해야합니다. 내 경우


는 가까운 실제로 exit()를 호출하기 전에 코드의 맨 마지막 문입니다.

TCP 스택이 전송 프로세스가 종료 된 후에도 실제로 데이터를 계속 전송하려고합니까? SO_LINGER를 설정하여 close()을 호출하기 전에 임의의 시간 초과를 기다리는 것만큼이나 신뢰할 만합니까?

즉, 동일한 TCP 타임 아웃이 적용됩니까? 아니면 더 짧습니까? 큰 보내기 버퍼와 느린 연결을 사용하면 버퍼링 된 모든 데이터를 실제로 전송할 시간이 상당히 길어질 수 있습니다.


마지막으로 보낸 바이트를 알리는 데 전혀 관심이 없습니다. 나는 단지 원격 호스트에 가능한 한 안정적으로 도달하도록하고 싶습니다.

응용 프로그램 계층 확인은 옵션이 아닙니다 (프로토콜은 HTTP이고 작은 서버를 작성합니다).

+0

구현에 따라 다르지만 일반적으로 예 ('close()'는 실제로 소켓을 뜯어 내기 전에 버퍼에 남아있는 데이터를 플러시합니다. close()를 호출하는 것 외에도 전체 프로세스를 종료하면 마일리지가 달라질 수 있습니다. – aroth

+2

@aroth 마일리지는 귀하가 절차를 종료하면 변경되지 않습니다. 두 가지 경우에는 차이가 없습니다. 반대를 유지하려면 신뢰할 수있는 참조를 제공하십시오. – EJP

+0

@EJP - 임의의 프로그램에서 * 발생할 수있는 권위있는 참조? 나는 그런 것이 존재한다고 생각하지 않는다. 그러나 그럴듯한 예를 제시하는 것은 간단합니다. 대부분의 프로그램처럼 별도의 스레드에 모든 네트워크 작업을 위임하는 프로그램이 있다고 가정 해보십시오. 백그라운드 스레드가'close()'를 호출하는 동안 주 스레드가 (정상적으로 또는 다른 방법으로) 프로세스를 종료 할 수 있습니다. 이 경우 통화가 성공할 것인가? 나는 그것을 의심한다. 허락하신다면, 당신이 말하는 것은 단일 스레드 프로그램에 적용되어야합니다. 그러나 모든 프로그램이 단일 스레드 인 것은 아닙니다. – aroth

답변

20

저는 많이 읽었습니다. ultimate SO_LINGER page. 나는 당신도 그것을 읽는 것이 좋습니다. TCP 소켓과 관련된 대용량 데이터 전송의 경우를 설명합니다.

나는 SO_LINGER의 전문가가 아니지만, (여전히 활성 개발 중) 내 서버 코드에 나는 다음을 수행하십시오

마지막 바이트가 전송()를 통해 전송 된 후
  1. , 나는 "전화 shutdown (sock, SHUT_WR) "을 사용하여 FIN 전송을 트리거합니다.

  2. 그런 다음 해당 소켓에서 후속 recv() 호출이 0을 반환 할 때까지 대기합니다 (recv는 -1을 반환하고 errno는 EAGAIN/EWOULDBLOCK 이외의 다른 것입니다).

  3. 그런 다음 서버는 소켓에서 close()를 수행합니다.

클라이언트는 응답의 모든 바이트를 수신 한 후 먼저 소켓을 닫을 것이라고 가정합니다.

그러나 마지막 send()와 recv() 사이에 EOF가 지정된 경우 시간 제한이 적용됩니다. 클라이언트가 연결 종료를 절대로 닫지 않으면 서버는 대기를 포기하고 어쨌든 연결을 닫습니다. 이 시간 초과로 45-90 초입니다.

모든 소켓이 비 블로킹이며 rec /() 또는 send()를 다시 호출 해 볼 시간인지 여부를 힌트로 연결 이벤트를 알리기 위해 poll/epoll을 사용합니다.

+2

클라이언트가 소켓을 먼저 닫는 한 아주 좋은 해결책 인 것 같습니다. 그러나 요청을 보낸 직후에 연결의 절반을 닫을 수는 없습니까? HTTP 사양은 절반 닫음과 관련하여 아무 것도 말하지 않습니다. 그 행동이 HTTP 클라이언트에서 발생한다고 생각합니까? – lxgr

+0

아니요. 유효성을 검사하기 위해 ad-hoc wireshark 스 니프를 수행했습니다. 나는 너에게 똑같이하도록 권하고 싶다. 내 패킷 스니핑 테스트에서 - 때로는 서버가 응답 후 FIN을 보내고 클라이언트는 응답을받은 후 FIN을 보냅니다. 그러나 대부분의 http 클라이언트는 어쨌든 서버에 "keep-alive"옵션을 지정하므로 클라이언트는 어쨌든 닫기를 시작하지 않습니다. 즉, 고객이 절반 가까이하지 않을 것이라고 가정하는 것이 매우 안전하다고 생각합니다. – selbie

+0

또한 클라이언트는 Content-Length 헤더에주의를 기울일 가능성이 큽니다. 클라이언트는 HTTP 리포지토리에서 예상되는 바이트 수를 알고 있기 때문에 서버가 모든 바이트를 보낸 후에 서버를 닫거나 종료 할 필요가 없다고 생각할 수도 있습니다. (연결 유지 기능을 지원하고 클라이언트가 요청한 경우 서버가 확실히 닫히지 않습니다. 그러나 keep-alive가없는 간단한 요청에서 서버는 응답을 보낸 후에 FIN을 전송합니다. – selbie