C++ boost:asio::read或boost:asio::async\u读取超时

C++ boost:asio::read或boost:asio::async\u读取超时,c++,boost-asio,asio,C++,Boost Asio,Asio,对。我知道在boost::asio中有一些关于超时的问题。我的问题可能太简单了,asio的人无法在这里解决 我正在使用TCP协议上的boost::asio,以尽可能快的速度通过网络以循环方式连续读取数据 在while循环中,从workerstd::thread连续调用以下函数ReadData() std::size_t ReadData(std::vector<unsigned char> & buffer, unsigned int size_to_read) { bo

对。我知道在
boost::asio
中有一些关于超时的问题。我的问题可能太简单了,
asio
的人无法在这里解决

我正在使用TCP协议上的
boost::asio
,以尽可能快的速度通过网络以循环方式连续读取数据

在while循环中,从worker
std::thread
连续调用以下函数
ReadData()

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;
}
std::size\u t ReadData(std::vector&buffer,unsigned int size\u to\u read){
boost::system::error\u code error\u code;
调整缓冲区大小(从大小到读取);
//接收体
std::size\u t bytes\u read=boost::asio::read(*m\u套接字,boost::asio::buffer(buffer),错误代码);
如果(字节数_读取==0){
//日志错误
返回;
}
返回读取的字节数;
}
它很好用。返回数据。一切都很好

我想要的就是对
boost::asio::read
使用超时。我了解到,我需要使用
boost::asio::async\u read
boost::asio::async\u wait
来让超时技术发挥作用

有人建议使用boost::asio::async\u read\u直到

我应该使用
boost::asio::async\u read
还是
boost::asio::async\u read\u直到

无论我使用的是
boost::asio::async\u read
还是
boost::asio::async\u read
boost::asio::read
。但是我希望在调用我的方法
ReadData
时触发并完成
asio::read
调用,这样客户端代码就不会受到影响


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

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

理由:

您似乎想要使用阻塞操作。既然如此,很有可能您没有运行线程来泵送io循环

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

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

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

#包括
模板
带超时的自动异步读取(流和流、ConstBufferSequence和sequence、std::size\t millis、处理程序和处理程序)
{
使用handler\u type=std::decation\u t;
使用缓冲区\u序列\u类型=标准::衰减\u t;
使用stream_type=stream;
结构状态\u机器:std::从此\u启用\u共享\u
{
状态机(流类型和流、缓冲区序列类型序列、处理程序类型处理程序)
:溪流(溪流)
,sequence_(std::move(sequence))
,处理程序(std::move(处理程序))
{}
无效开始(标准::大小\u t毫秒)
{
计时器从现在起过期(boost::posix_time::毫秒(毫秒));
timer_u.async_uwait(strand_uu.wrap([self=this->shared_ufrom_uthis()])(自动和自动){
自我->处理超时(ec);
}));
boost::asio::异步读取(流、序列、,
缠绕([self=this->shared_from_this()](自动和&ec,自动大小){
self->handle\u read(ec,大小);
}));
}
无效句柄超时(boost::system::error\u code const&ec)
{
如果(非ec和未完成)
{
boost::system::error\u代码接收器;
流(取消)(接收);;
}
}
无效句柄读取(boost::system::error\u code const&ec,std::size\u t size)
{
断言(未完成);
boost::system::error\u代码接收器;
定时器取消(接收器);
已完成=正确;
处理程序(ec,尺寸);
}
河流类型和河流类型;
缓冲区序列类型序列;
处理程序类型处理程序;
boost::asio::io_service::strand{stream_uu.get_io_service()};
boost::asio::deadline\u timer\u{stream\uu.get\u io\u service()};
bool completed=假;
};
自动psm=std::使_共享(流,
标准::正向(顺序),
std::转发(处理程序));
psm->启动(毫秒);
}
std::size\u t ReadData(boost::asio::ip::tcp::socket和socket,
标准::向量和缓冲区,
无符号整型大小\u到\u读取,
boost::system::错误(代码和ec){
调整缓冲区大小(从大小到读取);
ec.clear();
std::size\u t bytes\u read=0;
auto&executor=socket.get_io_service();
带超时的异步读取(套接字,boost::asio::buffer(buffer),
2000,//例如2秒
[&](自动&错误,自动大小){
ec=错误;
字节\读取=大小;
});
//todo:使用比生成线程更具可伸缩性的执行器
auto future=std::async(std::launch::async,[&]{
if(executor.stopped()){
executor.reset();
}
executor.run();
});
未来。等待();
返回读取的字节数;
}

您知道可以使用
socket::cancel()
取消异步操作,对吗?是的。我知道如果达到超时,我应该取消插座。但我首先如何在异步读取中使用超时呢?@量子物理学家。
socket::cancel()
是否可以处理同步读取操作?@SegmentationFault同时启动异步读取和异步等待。第一个完成的应该取消另一个。“您需要一个标志来指示您已取消,并且您希望使用一个串来管理线程争用。”QuantumPhysicator的回答已发布。建议您查看asio文档,了解我在这里使用的每种技术。asio很深,文档非常简洁。@SegmentationFault stream_类型是a
#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;
}