Pergunta

Existe uma maneira para cancelar uma operação pendente (sem desligar) ou definir um tempo limite para o aumento de biblioteca de funções?

I. e.Eu quero definir um tempo limite de bloqueio de tomada de impulso asio?

soquete.read_some(boost::asio::buffer(pData, maxSize), error_);

Exemplo:Eu quero ler alguns da tomada, mas quero lançar um erro se 10 segundos.

Foi útil?

Solução

Em Linux/BSD, o tempo limite nas operações de E/S nos soquetes é suportado diretamente pelo sistema operacional. A opção pode ser ativada via setsocktopt(). Eu não sei se boost::asio Fornece um método para defini -lo ou expõe o Socket Scripttor para permitir que você o defina diretamente - o último caso não é realmente portátil.

Por uma questão de completude, aqui está a descrição da página do homem:

SO_RCVTIMEO e 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.

Outras dicas

Quando essa pergunta foi feita, acho que a ASIO não teve nenhum exemplo de como realizar o que o OP precisava, ou seja, para limitar uma operação de bloqueio, como uma operação de soquete de bloqueio. Agora existem exemplos para mostrar exatamente como fazer isso. O exemplo parece longo, mas isso é porque é bem comentado. Ele mostra como usar o Modo ioservice em um tipo de 'tiro'.

Eu acho que o exemplo é uma ótima solução. As outras soluções aqui quebram a portabilidade e não aproveitam a ioservice. Se a portabilidade não for importante e o ioservice parece ser de muita sobrecarga-então-você não deve estar usando o ASIO. Não importa o que aconteça, você terá um iService criado (quase toda a funcionalidade da ASIO depende disso, até mesmo soquetes), então, aproveite -o.

Tempo limite uma operação bloqueadora do ASIO TCP

Tempo limite uma operação de UDP de ASIO bloqueador

A documentação da ASIO foi atualizada, portanto, confira novos exemplos sobre como superar alguns dos 'Gotchas' ASIO que costumam ter.

Você pode fazer um Async_read e também definir um cronômetro para o seu tempo desejado. Então, se o timer disparar, ligue para cancelar seu objeto de soquete. Caso contrário, se a sua leitura acontecer, você poderá cancelar seu cronômetro. Isso exige que você use um objeto io_service, é claro.

Editar: Encontrei um trecho de código para você que faz isso

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

Eu tinha a mesma pergunta e, depois de algumas pesquisas, a solução mais simples e limpa que eu poderia encontrar era obter o soquete nativo subjacente e fazer uma seleção até que houvesse dados para ler. Selecionar fará um parâmetro de tempo limite. Obviamente, trabalhar com o soquete nativo começa a ir contra o ponto de usar o ASIO em primeiro lugar, mas, novamente, esse parece ser o caminho mais limpo. Até onde eu sabia, a ASIO não fornece uma maneira de fazer isso para uso síncrono facilmente. Código:

        // 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);

        ...

Talvez isso seja útil para sua situação.

TL;DR

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

RESPOSTA COMPLETA Esta pergunta continua sendo perguntado repetidamente por muitos anos.Respostas que eu vi até agora são muito pobres.Vou adicionar esta informação aqui, em uma das primeiras ocorrências para esta pergunta.

Todo mundo tentando usar o ASIO para simplificar o seu código de rede seria perfeitamente feliz se o autor seria apenas adicionar um parâmetro opcional limite de tempo para todos de sincronização e de e / s assíncrona de funções.Infelizmente, é improvável que isso aconteça (na minha humilde opinião, apenas por razões ideológicas, depois de tudo, COMO em ASIO é por um motivo).

Então, estes são os caminhos para a pele este pobre gato disponíveis até o momento, nenhum deles especialmente apetitoso.Vamos dizer que nós precisamos de 200ms tempo de espera.

1) Bom (mau) idade API de socket:

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

Por favor, note essas peculiaridades:- const int timeout - no Windows o tipo é, na verdade, DWORD, mas o atual conjunto de compiladores felizmente, o mesmo, então, const int funciona tanto no Win e Posix mundo.- (const char*) para o valor.No Windows const char* é necessária, Posix requer const void*, em C++, const char* irá converter para const void*, silenciosamente, enquanto que o contrário não é verdadeiro.

Vantagens:obras e provavelmente sempre irá funcionar como a API de socket é antigo e estável.Bastante simples.Rápido.Desvantagens:tecnicamente pode exigir apropriado arquivos de cabeçalho (o que é diferente na Vitória e até mesmo diferentes sabores de UNIX) para setsockopt e as macros, mas a implementação atual do ASIO poluem o espaço de nomes global com eles de qualquer maneira.Requer uma variável para tempo limite.Não type-safe.No Windows, requer que o soquete é sobreposta modo de trabalho (do qual a corrente ASIO implementação felizmente usa, mas ainda é um detalhe de implementação).FEIA!

2) Personalizado ASIO opção de soquete:

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 });

Vantagens:Bastante simples.Rápido.Bela (com typedef).Desvantagens:Depende ASIO detalhe de implementação, o que pode mudar (mas OTOH tudo vai mudar, eventualmente, e tal detalhe é menos susceptível de alterar, em seguida, APIs públicas sujeitas à padronização).Mas caso isso aconteça, você terá que escrever uma classe de acordo com https://www.boost.org/doc/libs/1_68_0/doc/html/boost_asio/reference/SettableSocketOption.html (que é, obviamente, uma grande PITA, graças ao óbvio overengineering desta parte do ASIO) ou, melhor ainda reverter a 1.

3) Usar C++ async/futuras instalações.

#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;
    }

Vantagens:standard.Desvantagens:sempre inicia uma nova thread (na prática), o qual é relativamente lento (pode ser bom o suficiente para os clientes, mas vai levar para a vulnerabilidade DoS servidores como threads e sockets são "caros" de recursos).Não tente usar std::lançamento::créditos em vez de std::lançamento::assíncrono para evitar novo segmento de lançamento como wait_for sempre retornará future_status::créditos sem tentar executar o código.

4) O método prescrito pelo ASIO - utilizar operações assíncronas apenas (o que realmente não é a resposta para a pergunta).

Vantagens:bom o suficiente para servidores também se enorme escalabilidade para transações curtas não é necessário.Desvantagens:muito prolixo (então eu não vou nem incluir exemplos - ver ASIO exemplos).Requer muito cuidado gerenciamento do tempo de vida de todos os seus objetos usados tanto por operações assíncronas e a sua conclusão, os manipuladores, que, na prática, requer que todas as classes que contém e usar esses dados em operações assíncronas ser derivada a partir de enable_shared_from_this, que requer que todas as classes do tipo alocado no heap, o que significa que (pelo menos para o curto operações) que a escalabilidade vai começar a conicidade depois de cerca de 16 segmentos como cada pilha de alocação/dealloc vai usar uma barreira de memória.

Seguindo o que Grepsedawk mencionou. Existem alguns exemplos mostrando como cancelar operações assíncronas de longa duração após um período de tempo, sob o Tempo limite Seção dentro da ASIO DOCO. Aumente os exemplos da ASIO . O cliente TCP ASYNC me ajudou mais.

Feliz assíncula :)

Mesmo anos após a pergunta original, ainda não há uma resposta satisfatória.

Manualmente usar o Select não é uma boa opção

  1. O número do descritor de arquivo deve ser menor que 1024
  2. O FD pode ser relatado vazia como pronta devido à soma de verificação errada.

Ligar io_service.run_one() também é uma má ideia, porque pode haver outras opções de assíncronas que precisam de um io_service para sempre run(). E o documento do Boost sobre o bloqueio do cliente TCP é difícil de compreender.

Então aqui está minha solução. A idéia principal é o seguinte:

{
    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);
}

Aqui Semaphore é apenas um mutex e um condition_variable.
wait_for é implementado por http://en.cppreference.com/w/cpp/thread/condition_variable/wait_for

O código completo está em https://github.com/scinart/cpplib/blob/master/include/asio.hpp
Exemplos está dentro https://github.com/scinart/cpplib/blob/master/test/test_asio.cpp
Melhor exemplo em https://github.com/scinart/cpplib/blob/master/test/test_syncboostio.cpp

Você pode envolver as chamadas síncronas em futuros e aguardar a conclusão de um tempo limite (wait_timeout).

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

Certamente, não é um tamanho único, mas funciona bem para, por exemplo, contornar os tempos de conexão lenta.

No *nix, você usaria o alarme () para que sua chamada de soquete falhasse com o eintr

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top