2011-02-07 4 views
17

boost::asio을 비동기 적으로 사용하는 클라이언트와 서버가 있습니다. 몇 가지 시간 제한을 추가하여 연결을 닫고 문제가 발생하면 다시 시도 할 수 있습니다.부스트 :: asio 비동기 호출이 자동으로 시간 초과됩니까?

내 초기 생각은 async_ 함수를 호출 할 때마다 비동기 작업이 완료 될 것으로 예상되면 만료되도록 deadline_timer을 시작해야한다는 것입니다. 이제는 모든 상황에서 이것이 꼭 필요한 것인지 궁금합니다. 예를 들어

:

  • async_resolve 아마도 (아마도 /etc/resolv.conf 구성에 의해 무시 resolv.h에서 예컨대 RES_TIMEOUT) 그것에 내장 된 시간 제한을 갖는 시스템의 리졸버를 사용한다. 내 자신의 타이머를 추가함으로써, 사용자가 자신의 분석가가 일하기를 원하는 방식과 충돌 할 수 있습니다. async_connect를 들어

  • connect(2) 콜은 내장 타임 아웃의 일종을 가지고 그것을

그래서 async_ 호출이 내 자신의 핸들러를 호출 보장되는 (있는 경우)를 " 합리적인 "시간 프레임? 그리고 만약 작업이 타임 아웃을하면 처리기는 basic_errors::timed_out 오류를 전달할 것인가?

+0

내 자신의'deadline_timer'를 만드는 것에 전념해야했기 때문에 불필요한 것인지 매우 관심이있었습니다. – chrisaycock

+0

+1 흥미로운 질문입니다. 나는 그 대답이 대체로 플랫폼에 달려 있다고 생각한다. 나는 당신이 리눅스에 관심이 있다고 가정하고 있는가? –

답변

29

그래서 몇 가지 테스트를 수행했습니다. 내 결과에 따르면, 그들이 기반 OS 구현에 의존한다는 것은 분명합니다. 참고로 Fedora 커널을 가지고 테스트했습니다 : 2.6.35.10-74.fc14.x86_64.

결론은 async_resolve() 당신이 deadline_timer을 설정하지 않고 멀리 얻을 수있을 수있는 경우에만 것으로 보인다는 것이다. 합리적인 행동을 취하는 모든 다른 경우에는 실질적으로 필요합니다.


async_resolve()

async_resolve()에 대한 호출은 5 초 간격 4 개 쿼리의 결과. 처리기는 요청 후 오류가 boost::asio::error::host_not_found 인 20 초 후에 호출되었습니다.

My resolver는 기본적으로 2 초 동안 5 초의 시간 초과 (resolv.h)로 설정되어 있으므로 구성된 쿼리 수가 두 배로 보입니다. 동작은 options timeoutoptions attempts/etc/resolv.conf에 설정하여 수정할 수 있습니다. 모든 경우에 전송 된 쿼리의 수는 attempts으로 설정되었고 핸들러는 이후에 host_not_found 오류와 함께 호출되었습니다.

테스트의 경우 단일 구성된 네임 서버가 블랙홀 라우트되었습니다. 블랙홀 라우팅 대상으로 async_connect()를 호출

async_connect()


는 핸들러가 ~ 1백89초 후 오류 boost::asio::error::timed_out으로 호출되는 결과.

스택이 초기 SYN 및 5 회 재전송을 보냈습니다. 첫 번째 재 시도는 3 초 후에 전송되고 재시도 시간 초과는 매번 두 배가됩니다 (3 + 6 + 12 + 24 + 48 + 96 = 189). 재시도 횟수가 변경 될 수 있어야한다

[재전송 타이머]는 SYN 세그먼트 5의 디폴트는 RFC 1122 (4.2.3.5)에 부합하도록 선택된다

% sysctl net.ipv4.tcp_syn_retries 
net.ipv4.tcp_syn_retries = 5 
적어도 의 세그먼트를세그먼트의 재전송을 위해 3 분 이상으로 설정하십시오. 애플리케이션은 연결을 닫을 수 있습니다 (즉, 개방 시도를 포기할 수 있음). 물론 더 빠릅니다.

3 분 = 180 초이지만 RFC는 상한을 지정하지는 않습니다. 구현이 영원히 재 시도하는 것을 막을 수있는 방법은 없습니다. 소켓의 송신 버퍼가 가득 아니었다으로

async_write()


는 한,이 핸들러는 항상 바로 불렀다.

내 테스트에서 TCP 연결을 설정하고 1 분 후에 async_write()을 호출하는 타이머를 설정했습니다. 대상에 블랙홀 이후의 트래픽 다운 스트림 라우터를 설정

  • : 연결이 설정하지만 async_write() 호출하기 전에 한 분 동안, 나는 신체 상해의 모든 종류를 시도했다.
  • 대상의 스푸핑 된 RST로 응답하도록 다운 스트림 방화벽에서 세션을 지우는 중입니다.
  • 상관없이 내가 무슨 짓을했는지 /etc/init.d/network stop

를 실행하지 내 이더넷

  • 뽑기, 다음 async_write() 즉시 성공을보고 핸들러를 호출한다. 방화벽이 RST를 위장하는 경우

    은, 바로 연결이 닫혔습니다,하지만 난 알 방법이 없다고 내가 (이 즉시 boost::asio::error::connection_reset을보고 할 것)을 다음 작업을 시도 할 때까지. 다른 경우에는 17-18 분 후에 결과가 나올 때까지 연결이 열려 있고 오류를보고하지 않습니다.

    async_write()의 최악은 호스트가 재전송 중이며 송신 버퍼가 가득 찬 경우입니다.버퍼가 가득 차면 async_write()은 재전송 시간이 초과 될 때까지 처리기를 호출하지 않습니다. 15 재전송 리눅스 기본값 : 재전송 사이

    % sysctl net.ipv4.tcp_retries2 
    net.ipv4.tcp_retries2 = 15 
    

    시간 각각 이후에 증가 (그리고 여러 요인에 기초 같은 특정 연결의 추정 왕복 시간으로) 그러나 이분에 클램프된다. 따라서 기본 15 번의 재전송과 최악의 경우 2 분의 시간 제한을 사용하면 async_write() 처리기를 호출하기위한 상한선은 30 분입니다. 호출 될 때 오류는 boost::asio::error::timed_out으로 설정됩니다.

    async_read()


    는 한 연결이 설정 및 데이터가 수신되지로 핸들러를 호출해서는 안됩니다. 나는 그것을 시험 할 시간이 없었다.

  • +2

    이 답변은 ... 내 짧은 답변보다 훨씬 더 자세한 내용을 제공해야합니다. – diverscuba23

    10

    두 번의 호출에는 처리기까지 시간 초과가 지정 될 수 있지만 시간 초과가 발생할 때까지 기다릴 수 있습니다. (연결을 그냥 앉아서 프로세스를 죽이기 전에 boost::asio와 10 분 이상 연결하는 단일 연결을 시도했다는 것을 알고 있습니다.) 또한 async_readasync_write 호출에는 시간 초과가 연결되지 않으므로 읽기 및 쓰기에 시간 초과를 원할 경우 deadline_timer이 필요합니다.

    +1

    +1 의심 스럽다면 명백해야합니다. 행동이 문서화되지 않은 경우 자신의 타이머를 추가하십시오. –

    +0

    예. 이것은 내가 발견 한 것입니다. 'async_read'와'async_write' * do *는 과도한 재전송으로 인해 결국 수십 분 후에 연결이 닫히게된다는 의미에서 타임 아웃이 있습니다. – eater

    관련 문제