boost: asio :: read или boost: asio :: async_read с тайм-аутом

Да. Я знаю, что было несколько вопросов вокруг этого time_out в boost::asio, Моя проблема может быть слишком простой для asio ребята, чтобы решить здесь.

я использую boost::asio по протоколу TCP, чтобы читать данные по сети непрерывно в цикле так быстро, как я могу.

Следующая функция ReadData() непрерывно вызывается от работника std::thread в то время как цикл.

std::size_t ReadData(std::vector<unsigned char> & buffer, unsigned int size_to_read) {

boost::system::error_code error_code;
buffer.resize(size_to_read);

// Receive body
std::size_t bytes_read = boost::asio::read(*m_socket, boost::asio::buffer(buffer), error_code);

if (bytes_read == 0) {
// log error
return;
}

return bytes_read;
}

Работает нормально. Возвращает данные. Все хорошо.

Все, что я хочу, это использовать time_out для boost::asio::read, Я узнал, что мне нужно использовать boost::asio::async_read с boost::asio::async_wait для техники time_out для работы.

Один пример повышения предлагает использовать boost::asio::async_read_until ?

Должен ли я использовать boost::asio::async_read или же boost::asio::async_read_until ?

Неважно, использую ли я boost::asio::async_read или же boost::asio::async_read_until или же boost::asio::read, Но я хочу asio::read призыв к срабатыванию & сделано в рамках вызова моего метода ReadData чтобы клиентский код не пострадал.

Как мне этого добиться? Пожалуйста, предложите

0

Решение

ОК, что-то вроде этого должно соответствовать вашей цели:

Обоснование:

Вы, кажется, хотите использовать операции блокировки. Так как это так, есть большая вероятность, что вы не запускаете поток для прокачки цикла ввода-вывода.

Таким образом, мы запускаем две асинхронные задачи в цикле io сокета, а затем создаем поток для:

а) сбросить (фактически перезапустить) цикл, если он уже исчерпан

б) запустить цикл до истощения (мы могли бы быть умнее здесь и запускать его только до тех пор, пока обработчик не покажет, что какое-то условие выполнено, но это урок для другого дня)

#include <type_traits>

template<class Stream, class ConstBufferSequence, class Handler>
auto async_read_with_timeout(Stream& stream, ConstBufferSequence&& sequence, std::size_t millis, Handler&& handler)
{
using handler_type = std::decay_t<Handler>;
using buffer_sequence_type = std::decay_t<ConstBufferSequence>;
using stream_type = Stream;

struct state_machine : std::enable_shared_from_this<state_machine>
{
state_machine(stream_type& stream, buffer_sequence_type sequence, handler_type handler)
: stream_(stream)
, sequence_(std::move(sequence))
, handler_(std::move(handler))
{}
void start(std::size_t millis)
{
timer_.expires_from_now(boost::posix_time::milliseconds(millis));
timer_.async_wait(strand_.wrap([self = this->shared_from_this()](auto&& ec) {
self->handle_timeout(ec);
}));
boost::asio::async_read(stream_, sequence_,
strand_.wrap([self = this->shared_from_this()](auto&& ec, auto size){
self->handle_read(ec, size);
}));
}

void handle_timeout(boost::system::error_code const& ec)
{
if (not ec and not completed_)
{
boost::system::error_code sink;
stream_.cancel(sink);
}
}

void handle_read(boost::system::error_code const& ec, std::size_t size)
{
assert(not completed_);
boost::system::error_code sink;
timer_.cancel(sink);
completed_ = true;
handler_(ec, size);
}

stream_type& stream_;
buffer_sequence_type sequence_;
handler_type handler_;
boost::asio::io_service::strand strand_ { stream_.get_io_service() };
boost::asio::deadline_timer timer_ { stream_.get_io_service() };
bool completed_ = false;
};

auto psm = std::make_shared<state_machine>(stream,
std::forward<ConstBufferSequence>(sequence),
std::forward<Handler>(handler));
psm->start(millis);
}

std::size_t ReadData(boost::asio::ip::tcp::socket& socket,
std::vector<unsigned char> & buffer,
unsigned int size_to_read,
boost::system::error_code& ec) {

buffer.resize(size_to_read);

ec.clear();
std::size_t bytes_read = 0;
auto& executor = socket.get_io_service();
async_read_with_timeout(socket, boost::asio::buffer(buffer),
2000, // 2 seconds for example
[&](auto&& err, auto size){
ec = err;
bytes_read = size;
});

// todo: use a more scalable executor than spawning threads
auto future = std::async(std::launch::async, [&] {
if (executor.stopped()) {
executor.reset();
}
executor.run();
});
future.wait();

return bytes_read;
}
1

Другие решения

Других решений пока нет …