Boost ASIO에서 소켓 차단에서 타임 아웃을 설정하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/291871

  •  08-07-2019
  •  | 
  •  

문제

보류중인 작업을 취소하거나 (연결을 끊지 않은) Boost 라이브러리 기능에 대한 타임 아웃을 설정하는 방법이 있습니까?

즉, Boost ASIO에서 소켓 차단에서 타임 아웃을 설정하고 싶습니까?

socket.read_some (boost :: asio :: buffer (pdata, maxsize), error_);

예 : 소켓에서 일부를 읽고 싶지만 10 초가 지나면 오류를 던지고 싶습니다.

도움이 되었습니까?

해결책

Linux/BSD에서 소켓의 I/O 작업 시간 초과는 운영 체제에서 직접 지원됩니다. 옵션을 통해 옵션을 활성화 할 수 있습니다 setsocktopt(). 나는 모르겠다 boost::asio 설정 방법을 제공하거나 소켓 스크립트를 노출하여 직접 설정할 수 있도록 소켓 스크립트를 노출시킵니다. 후자의 경우는 실제로 휴대용이 아닙니다.

완전성을 위해 여기에 Man Page의 설명이 있습니다.

SO_RCVTIMEO 그리고 SO_SNDTIMEO

          Specify the receiving or sending  timeouts  until  reporting  an
          error.  The argument is a struct timeval.  If an input or output
          function blocks for this period of time, and data has been  sent
          or  received,  the  return  value  of  that function will be the
          amount of data transferred; if no data has been transferred  and
          the  timeout has been reached then -1 is returned with errno set
          to EAGAIN or EWOULDBLOCK just as if the socket was specified  to
          be  non-blocking.   If  the timeout is set to zero (the default)
          then the operation  will  never  timeout.   Timeouts  only  have
          effect  for system calls that perform socket I/O (e.g., read(2),
          recvmsg(2), send(2), sendmsg(2)); timeouts have  no  effect  for
          select(2), poll(2), epoll_wait(2), etc.

다른 팁

이 질문이 질문을 받았을 때, ASIO는 OP가 필요한 것을 달성하는 방법에 대한 사례가 없다고 생각합니다. 이제이 작업을 수행하는 방법을 정확하게 보여주는 예가 있습니다. 그 예는 길어 보이지만, 그것은 잘 댓글을 달기 때문입니다. '원사'종류의 모드에서 ioservice를 사용하는 방법을 보여줍니다.

그 예는 훌륭한 해결책이라고 생각합니다. 여기서 다른 솔루션은 이식성을 깨고 ioservice를 활용하지 않습니다. 이식성이 중요하지 않고 ioservice가 많은 오버 헤드처럼 보인다면 ASIO를 사용해서는 안됩니다. 어쨌든, 당신은 ioService를 만들어 낼 것입니다 (거의 모든 ASIO 기능은 동기화 소켓에 따라 다릅니다).

차단 ASIO TCP 작업 시간 초과

차단 ASIO UDP 작업 시간 초과

ASIO 문서가 업데이트되었으므로 'gotchas'ASIO를 사용하는 방법에 대한 새로운 예를 확인하십시오.

Async_read를 수행하고 원하는 시간 초과를위한 타이머를 설정할 수도 있습니다. 그런 다음 타이머가 발생하면 소켓 객체에서 취소를 호출하십시오. 그렇지 않으면 읽기가 발생하면 타이머를 취소 할 수 있습니다. 물론 IO_Service 객체를 사용해야합니다.

편집 :이 작업을 수행하는 코드 스 니펫을 찾았습니다.

http://lists.boost.org/archives/boost/2007/04/120339.php

나는 같은 질문을했고, 연구 후에, 내가 생각해 낼 수있는 가장 단순하고 깨끗한 해결책은 기본 원시 소켓을 얻고 읽을 데이터가있을 때까지 선택을하는 것이 었습니다. Select는 시간 초과 매개 변수를 사용합니다. 물론, 기본 소켓과의 작업은 처음에 ASIO를 사용하는 시점에 대항하기 시작하지만, 이것은 가장 깨끗한 방법 인 것 같습니다. 내가 알 수있는 한, ASIO는 동기식 사용을 쉽게 수행 할 수있는 방법을 제공하지 않습니다. 암호:

        // socket here is:  boost::shared_ptr<boost::asio::ip::tcp::socket> a_socket_ptr

        // Set up a timed select call, so we can handle timeout cases.

        fd_set fileDescriptorSet;
        struct timeval timeStruct;

        // set the timeout to 30 seconds
        timeStruct.tv_sec = 30;
        timeStruct.tv_usec = 0;
        FD_ZERO(&fileDescriptorSet);

        // We'll need to get the underlying native socket for this select call, in order
        // to add a simple timeout on the read:

        int nativeSocket = a_socket_ptr->native();

        FD_SET(nativeSocket,&fileDescriptorSet);

        select(nativeSocket+1,&fileDescriptorSet,NULL,NULL,&timeStruct);

        if(!FD_ISSET(nativeSocket,&fileDescriptorSet)){ // timeout

                std::string sMsg("TIMEOUT on read client data. Client IP: ");

                sMsg.append(a_socket_ptr->remote_endpoint().address().to_string());

                throw MyException(sMsg);
        }

        // now we know there's something to read, so read
        boost::system::error_code error;
        size_t iBytesRead = a_socket_ptr->read_some(boost::asio::buffer(myVector), error);

        ...

아마도 이것은 당신의 상황에 유용 할 것입니다.

tl; dr

socket.set_option(boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO>{ 200 });

완전한 답변이 질문은 몇 년 동안 계속해서 계속해서 요청을 받고 있습니다. 내가 지금까지 본 대답은 상당히 가난하다. 이 질문의 첫 번째 사건 중 하나 에이 정보를 여기에 추가하겠습니다.

ASIO를 사용하여 네트워킹 코드를 단순화하려는 모든 사람은 저자가 모든 동기화 및 Async IO 함수에 옵션 매개 변수 타임 아웃을 추가하면 완벽하게 행복 할 것입니다. 불행히도, 이것은 거의 일어나지 않을 것입니다 (Asio에서와 같이 이데올로기 적 이유 때문에, 이데올로기 적 이유 때문에).

그래서 이것들은 지금까지 이용 불쌍한 고양이를 피부를 피우는 방법입니다. 200ms 타임 아웃이 필요하다고 가정 해 봅시다.

1) 좋은 (나쁜) 오래된 소켓 API :

const int timeout = 200;
::setsockopt(socket.native_handle(), SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof timeout);//SO_SNDTIMEO for send ops

이러한 특성에 주목하십시오 .- 시간 초과를위한 const int -Windows에서 필요한 유형은 실제로 dword이지만, 현재 컴파일러 세트는 운 좋게도 동일하므로 const int는 Win과 Posix World에서 모두 작동합니다. - (const char*) 가치. Windows에서 const char*가 필요합니다. posix는 const void*를 필요로합니다.

장점 : 작동하며 소켓 API가 오래되고 안정적이기 때문에 항상 작동합니다. 충분히 간단합니다. 빠른. 단점 : 기술적으로 SetSockopt 및 Macros에 적합한 헤더 파일 (승리 및 Unix 풍미가 다름)이 필요할 수 있지만 현재 ASIO의 구현은 어쨌든 글로벌 네임 스페이스를 오염시킵니다. 타임 아웃에 변수가 필요합니다. 유형-안전하지 않습니다. Windows에서는 소켓이 중첩 모드에 있어야합니다 (현재 ASIO 구현이 운 좋게 사용하지만 여전히 구현 세부 사항입니다). 못생긴!

2) 사용자 정의 ASIO 소켓 옵션 :

typedef boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO> rcv_timeout_option; //somewhere in your headers to be used everywhere you need it
//...
socket.set_option(rcv_timeout_option{ 200 });

장점 : 충분히 간단합니다. 빠른. 아름다운 (typedef와 함께). 단점 : ASIO 구현 세부 사항에 따라 달라질 수 있습니다 (그러나 OTOH 모든 것이 결국 변경 될 것이며, 그러한 세부 사항은 표준화에 따라 공개 API가 변경 될 가능성이 적습니다). 그러나 이런 일이 발생하면 다음에 따라 수업을 작성해야합니다. https://www.boost.org/doc/libs/1_68_0/doc/html/boost_asio/reference/settablesocketoption.html (물론 ASIO 의이 부분에 대한 명백한 오버 엔지니어링 덕분에 주요 피타입니다) 또는 더 나은 것은 1로 되돌립니다.

3) C ++ 비동기/미래 시설을 사용하십시오.

#include <future>
#include <chrono>
//...
auto status = std::async(std::launch::async, [&] (){ /*your stream ops*/ })
    .wait_for(std::chrono::milliseconds{ 200 });
switch (status)
    {
    case std::future_status::deferred:
    //... should never happen with std::launch::async
        break;
    case std::future_status::ready:
    //...
        break;
    case std::future_status::timeout:
    //...
        break;
    }

장점 : 표준. 단점 : 항상 새로운 스레드 (실제로)를 시작하는데, 이는 비교적 느리게 (클라이언트에게는 충분할 수 있지만 스레드와 소켓이 "비싸다"리소스이므로 서버의 DOS 취약성으로 이어질 것입니다). wait_for가 항상 미래의 _status :: 코드를 실행하지 않고 연기되므로 새 스레드를 방지하기 위해 std :: unlak :: deferred를 사용하려고 시도하지 마십시오.

4) ASIO가 규정 한 방법 - 비동기 연산 만 사용합니다 (실제로 질문에 대한 답이 아님).

장점 : 짧은 트랜잭션의 엄청난 확장 성이 필요하지 않은 경우 서버에도 충분합니다. 단점 : 상당히 말이 많습니다 (따라서 예제조차 포함하지 않을 것입니다 - ASIO 예를 참조하십시오). 비동기 작업 및 완료 처리기 모두에서 사용하는 모든 객체를 매우 신중하게 수명 관리해야합니다. 실제로 Async 작업에 그러한 데이터를 포함하고 사용하는 모든 클래스는 ENABLE_SHARERARED_FROM_THIS에서 파생되어야하며, 이는 HEAP에 할당 된 모든 클래스가 필요합니다. 적어도 짧은 작업의 경우) 모든 힙/딜 로크가 메모리 장벽을 사용하므로 확장 성이 약 16 개의 스레드 후에 테이퍼가 시작됩니다.

Grepsedawk가 언급 한 내용을 따르십시오. 일정 기간 후에 장기적으로 비동기 연산을 취소하는 방법을 보여주는 몇 가지 예가 있습니다. 타임 아웃 Asio Doco 내 섹션. ASIO 예를 높이십시오 . 비동기 TCP 클라이언트가 가장 도움이되었습니다.

행복한 비동기 :)

원래의 질문 이후 몇 년이 지나도 여전히 만족스러운 대답은 없습니다.

select를 수동으로 사용하는 것은 좋은 옵션이 아닙니다

  1. 파일 디스크립터 번호는 1024보다 작아야합니다
  2. FD는 잘못된 체크섬으로 인해 준비된 것으로 의심으로보고 될 수 있습니다.

부르다 io_service.run_one() 항상 IO_Service가 필요한 다른 비동기 옵션이있을 수 있기 때문에 나쁜 생각입니다. run(). 또한 TCP 클라이언트 차단에 대한 Boost의 문서는 이해하기 어렵습니다.

그래서 여기 내 해결책이 있습니다. 주요 아이디어는 다음과 같습니다.

{
    Semaphore r_sem;
    boost::system::error_code r_ec;
    boost::asio::async_read(s,buffer,
                            [this, &r_ec, &r_sem](const boost::system::error_code& ec_, size_t) {
                                r_ec=ec_;
                                r_sem.notify();
                            });
    if(!r_sem.wait_for(std::chrono::seconds(3))) // wait for 3 seconds
    {
        s.cancel();
        r_sem.wait();
        throw boost::system::system_error(boost::asio::error::try_again);
    }
    else if(r_ec)
        throw boost::system::system_error(r_ec);
}

여기 Semaphore 단지 뮤 테스와 조건 _variable입니다.
wait_for 구현됩니다 http://en.cppreference.com/w/cpp/thread/condition_variable/wait_for

전체 코드가 있습니다 https://github.com/scinart/cpplib/blob/master/include/asio.hpp
예가 있습니다 https://github.com/scinart/cpplib/blob/master/test/test_asio.cpp
더 나은 예 https://github.com/scinart/cpplib/blob/master/test/test_syncboostio.cpp

동기 호출을 선물로 랩핑하고 타임 아웃 (Wait_Timeout)으로 완료되기를 기다릴 수 있습니다.

http://www.boost.org/doc/libs/1_47_0/doc/html/thread/synchronization.html#thread.synchronization.futures

확실히 하나의 크기가 모두 적합하지는 않지만 예를 들어 느린 연결 시간 초과를 우회하는 데 적합합니다.

on *nix, 당신은 alarm ()을 사용하여 소켓 호출이 eintr로 실패합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top