boost:asio :: read或boost:asio :: async_read超时 [英] boost:asio::read or boost:asio::async_read with timeout

查看:307
本文介绍了boost:asio :: read或boost:asio :: async_read超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是的。我知道在 boost :: asio 中的 time_out 周围存在一些问题。对于 asio 的人来说,我的问题可能太简单了,无法在这里解决。

Yes. I know there have been a few questions around this time_out in boost::asio. My problem might to too simple for the asio guys to solve here.

我正在使用 boost :: asio 在TCP协议上以最快的速度连续不断地通过网络读取数据。

I am using boost::asio on TCP protocol to read data over a network continuously in a loop as fast as I can.

以下功能 ReadData()在while循环中不断从工作人员 std :: thread 调用。

Following function ReadData() gets called continuously from a worker std::thread in a while loop.

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 一起使用超时技术起作用。

All I want, is to use a time_out for the boost::asio::read. I learnt that I need to use boost::asio::async_read with boost::asio::async_wait for the time_out technique to work.

一个建议使用 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 的调用中完成,这样客户端代码不会受到影响。

It does not matter whether I use boost::asio::async_read or boost::asio::async_read_until or boost::asio::read. But I want the asio::read call to be triggered & done within the call to my method ReadData so that the client code does not get affected.

如何实现?请建议

推荐答案

好的,这样的东西应该适合您的目的:

OK, something like this should suit your purpose:

理性:

您似乎想使用阻止操作。既然是这种情况,那么很有可能您没有运行线程来泵送io循环。

You appear to want to use blocking operations. Since that is the case, there is a good chance that you're not running a thread to pump the io loop.

因此,我们启动了两个同时执行的异步任务套接字的io循环,然后产生一个线程以进行操作:

So we kick off two simultaneous async tasks on the socket's io loop and then spawn a thread to:

a)重置(实际上是重新启动)该循环,以防万一它已经用完了

a) reset (actually restart) the loop in case it's already been exhausted

b)循环运行到精疲力尽(我们可能会更聪明,只在处理程序表明已满足某些条件之前运行它,但这是另一天的教训)

b) run the loop to exhaustion (we could be cleverer here and only run it until the handler has indicated that some condition has been met, but that's a lesson for another day)

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

这篇关于boost:asio :: read或boost:asio :: async_read超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆