首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >boost:asio::read或带有超时的boost:asio::async_read

boost:asio::read或带有超时的boost:asio::async_read
EN

Stack Overflow用户
提问于 2017-04-03 19:36:20
回答 1查看 3.5K关注 0票数 2

是。我知道在time_out in boost::asio上有几个问题。我的问题可能太简单了,asio的人在这里解决不了。

我正在使用TCP协议上的boost::asio以尽可能快的速度在一个循环中连续读取网络上的数据。

下面的函数ReadData()在gets循环中不断地从worker std::thread调用。

代码语言:javascript
复制
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;
}

效果很好。返回数据。平安无事。

我想要的是,boost::asio::read使用time_out。我了解到,我需要使用boost::asio::async_readboost::asio::async_wait,以使time_out技术发挥作用。

有一个boost示例建议使用boost::asio::async_read_until

我应该使用boost::asio::async_read还是boost::asio::async_read_until

无论我是使用boost::asio::async_readboost::asio::async_read_until还是boost::asio::read,都不重要。但是我希望asio::read调用被触发&在调用我的方法ReadData中完成,这样客户端代码就不会受到影响。

我怎样才能做到这一点?请建议

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-03 20:49:42

好吧,像这样的东西应该适合你的目的:

理由:

您似乎希望使用阻塞操作。因为是这样的,所以很有可能您不会运行线程来驱动io循环。

因此,我们在套接字的io循环上同时启动两个异步任务,然后生成一个线程:

( a)重新设置(实际上重新启动)循环,以防它已经耗尽

( b)运行循环到耗尽(我们在这里可能更聪明,并且只运行它直到处理程序指示某些条件已经满足为止,但这是另一天的教训)

代码语言:javascript
复制
#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;
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43192898

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档