2015-12-12 3 views
1

У меня есть функция под названием read_packet. Эта функция остается заблокированной, пока нет запроса на соединение, или таймер сигнализируется.Boost.Asio: Почему таймер выполняется только один раз?

Код следующее:

std::size_t read_packet(const std::chrono::milliseconds& timeout, 
          boost::system::error_code& error) 
    { 
     // m_timer_ --> boost::asio::high_resolution_timer 

     if(!m_is_first_time_) { 
     m_is_first_time = true; 

     // Set an expiry time relative to now. 
     m_timer_.expires_from_now(timeout); 
     } else { 
     m_timer_.expires_at(m_timer_.expires_at() + timeout); 
     } 

     // Start an asynchronous wait. 
     m_timer_.async_wait(
      [ this ](const boost::system::error_code& error){ 
      if(!error) m_is_timeout_signaled_ = true; 
      } 
    ); 

     auto result = m_io_service_.run_one(); 

     if(!m_is_timeout_signaled_) { 
     m_timer_.cancel(); 
     } 

     m_io_service_.reset(); 

     return result; 
    } 

Функция работает корректно, пока не получает запрос на соединение. Все принятые запросы являются асинхронными.

После принятия соединения функция run_one() не блокирует время, заданное таймером. Функция всегда возвращает 1 (обрабатывается один дескриптор). Этот дескриптор соответствует таймеру.

Я не понимаю, почему возникает эта ситуация.

Почему функция не блокирует время, необходимое для таймера?

Cheers.

ПРИМЕЧАНИЕ: эта функция используется в цикле.

UPDATE:

У меня есть своя io_service::run() функции. Эта функция выполняет другие действия и задачи. Я хочу слушать и обрабатывать сетевой уровень за определенный период времени:

  • Если что-то идет на уровне сети, io_service::run_one() возвращается и read_packet() возвращает управление моих запуска() функции.

  • В противном случае таймер срабатывает и read_packet() возвращает управление к моей перспективе() функции.

Все, что поступает с сетевого уровня, хранится в структуре данных. Затем моя функция run() работает с этой структурой данных. Он также запускает другие варианты.

void run(duration timeout, boost::system::error_code& error) 
    { 
     time_point start = clock_type::now(); 
     time_point deadline = start + timeout; 

     while(!stop()) { 
      read_packet(timeout, error); 
      if(error) return; 

      if(is_timeout_expired(start, deadline, timeout)) return; 

      // processing network level 

      // other actions 
     } 
    } 

В моем случае сокеты всегда активны, пока клиент не запросит закрытие соединения.

В течение временного интервала вы управляете уровнем сети, а для другого слота вы занимаетесь другими вещами.

+0

Почему вы запускаете 'run_one', а не' run'? Кажется, что вы только один раз ждали, почему вы ожидаете, что таймер будет работать более одного раза? – sehe

+0

@sehe: У меня есть асинхронный акцептор. По этой причине функция 'io_service :: run()' всегда заблокирована. Пока я жду подключения, я хочу выполнять другие задачи. Таймер позволяет мне это делать. –

+0

Пожалуйста, посмотрите на некоторые образцы. Похоже, вы гремете против потока. Можете ли вы использовать поток для ввода-вывода или выполнять задания для ответных задач? Кроме того, это звучит как полное противоречие. Если вы используете таймеры для обратного вызова своего wiel, чтобы сделать в это время, в чем проблема с запуском, который не возвращается? Таймер по-прежнему будет гореть – sehe

ответ

0

ОК, код неправильный. Когда таймер отменяется, обработчик таймера всегда выполняется. По этой причине функция io_service::run_one() никогда не блокируется.

Дополнительная информация: basic_waitable_timer::cancel

Спасибо за помощь.

0

Прочитав вопрос более внимательно, я понял, что вы на самом деле пытаетесь использовать Asio для получения синхронного ввода-вывода, но с таймаутом в каждой операции чтения.

Это не то, для чего предназначался Asio (отсюда и название «Асинхронная библиотека IO»).

Но, конечно, вы можете это сделать, если настаиваете. Как я уже сказал, я чувствую, что ты слишком много.

В обработчике завершения вашего таймера просто отмените операцию сокета, если таймер истек. (Обратите внимание, что если это не так, вы получите operation_aborted, поэтому проверьте код ошибки).

Малый selfcontained пример (который является то, что вы всегда должны делать, когда пытаются получить помощь, кстати):

Live On Coliru

#include <boost/asio.hpp> 
#include <boost/asio/high_resolution_timer.hpp> 
#include <iostream> 

struct Program { 

    Program() { sock_.connect({ boost::asio::ip::address_v4{}, 6771 }); } 

    std::size_t read_packet(const std::chrono::milliseconds &timeout, boost::system::error_code &error) { 
     m_io_service_.reset(); 

     boost::asio::high_resolution_timer timer { m_io_service_, timeout }; 

     timer.async_wait([&](boost::system::error_code) { 
       sock_.cancel(); 
      }); 

     size_t transferred = 0; 
     boost::asio::async_read(sock_, boost::asio::buffer(buffer_), [&](boost::system::error_code ec, size_t tx) { 
        error  = ec; 
        transferred = tx; 
       }); 

     m_io_service_.run(); 

     return transferred; 
    } 

    private: 
    boost::asio::io_service m_io_service_; 
    using tcp = boost::asio::ip::tcp; 

    tcp::socket sock_{ m_io_service_ }; 
    std::array<char, 512> buffer_; 
}; 

int main() { 
    Program client; 
    boost::system::error_code ec; 

    while (!ec) { 
     client.read_packet(std::chrono::milliseconds(100), ec); 
    } 

    std::cout << "Exited with '" << ec.message() << "'\n"; // operation canceled in case of timeout 
} 

Если операция сокета успешно вы можете увидеть например:

Exited with 'End of file' 

В противном случае, если o peration не завершается в течение 100 миллисекунд, он будет печатать:

Exited with 'Operation canceled' 

Смотрите также await_operation в этом предыдущем ответе, обобщающего эту модель немного больше:

+0

См. Записанный прямой эфир на случай, если вам интересно, как я иду процесс чтения/ответа: https://www.livecoding.tv/video/repeatable-receive-operation-under-the-timeout/ – sehe

+0

Извините, но мой английский очень плохой, и я не могу объяснить. Это не совсем то, что я хочу. Я редактировал поток, добавляя дополнительную информацию. –

Смежные вопросы