我正在尝试使用Boost::asio和async_read在使用串行端口的协议(protocol)中实现超时。
我已经使用同步读取完成了一个测试实现,只能通过查找来实现,但是超时的实现不起作用。
void set_result( boost::optional<boost::system::error_code> * a, boost::system::error_code b ) {
a->reset( b );
}
void receive(boost::asio::io_service & io, boost::asio::serial_port & cctalk_port, boost::asio::streambuf & result){
#if 1
// Non-working implementation with timeout
boost::optional<boost::system::error_code> timer_result;
boost::optional<boost::system::error_code> read_result;
boost::asio::deadline_timer timer( io );
LOG(INFO) << "Timer at 5000ms starts here";
timer.expires_from_now( boost::posix_time::milliseconds(5000) ); // allow up to 50ms of timeout for every char
timer.async_wait( boost::bind(&set_result, &timer_result, _1) );
LOG(INFO) << "Async read starts here (result.size() == " << result.size() << ")";
boost::asio::async_read(
cctalk_port,
result,
boost::asio::transfer_at_least(1),
boost::bind( &set_result, &read_result, _1 ));
boost::system::error_code ec;
while(1) {
io.poll_one(ec);
if( ec != 0 || read_result != 0 || timer_result != 0)
LOG(INFO) << "Error code: " << ec << " read_result: " << read_result << " timer_result: " << timer_result;
if ( read_result ) {
timer.cancel();
LOG(INFO) << "Result ready (" << result.size() << ")";
return;
} else if ( timer_result ) {
LOG(INFO) << "Timeout";
throw runtime_error("timeout");
}
}
LOG(INFO) << "Not suppose to happen";
#else
// Working implementation without timeout
boost::asio::read(cctalk_port, result, boost::asio::transfer_at_least(1));
#endif
}
void receive(boost::asio::io_service & io, boost::asio::serial_port & cctalk_port, size_t size, boost::asio::streambuf & result){
LOG(INFO) << "Fetch at least " << size << " has allready: " << result.size();
while( result.size() < size ) {
receive(io, cctalk_port, result);
LOG(INFO) << "Buffer size: " << result.size() << "/" << size;
}
}
运行此代码时,我得到以下输出:
I0808 17:25:40.809615 3682 ccTalkScan.cxx:137] Fetch at least 5 has allready: 0
I0808 17:25:40.809672 3682 ccTalkScan.cxx:99] Timer at 5000ms starts here
I0808 17:25:40.809686 3682 ccTalkScan.cxx:103] Async read starts here (result.size() == 0)
I0808 17:25:40.809731 3682 ccTalkScan.cxx:115] Error code: system:0 read_result: 1 timer_result: 0
I0808 17:25:40.809738 3682 ccTalkScan.cxx:119] Result ready (12)
I0808 17:25:40.809742 3682 ccTalkScan.cxx:140] Buffer size: 12/5
I0808 17:25:40.809778 3682 ccTalkScan.cxx:137] Fetch at least 5 has allready: 7
I0808 17:25:40.809783 3682 ccTalkScan.cxx:137] Fetch at least 9 has allready: 7
I0808 17:25:40.809788 3682 ccTalkScan.cxx:99] Timer at 5000ms starts here
I0808 17:25:40.809797 3682 ccTalkScan.cxx:103] Async read starts here (result.size() == 7)
I0808 17:25:40.809808 3682 ccTalkScan.cxx:115] Error code: system:0 read_result: 0 timer_result: 1
I0808 17:25:40.809811 3682 ccTalkScan.cxx:123] Timeout
从输出中可以看到,计时器的设置必须快于5000ms,在这种情况下必须少于1ms。
而且,通过查看实际收到的字节,我似乎丢失了第一个字节。
最佳答案
嗯...这里的问题很细微,基本上是当您取消上一个计时器时-io_service上触发了另一个事件(对负责该计时器的处理程序的调用),以表明它已被取消(带有相应的error_code)。因为您只调用poll_one
,所以读取很容易进行,因此您可以处理读取,然后取消计时器(这将在io_service上设置后续事件-但对于此运行,不会调用该事件)-然后当您再次调用receive()
方法并调用poll_one
时-触发了此事件(并且因为您没有检查set_result
方法中的错误情况),可选参数的状态很好(它包含错误),并且您将此视为您的超时...
跟随?
关于c++ - Boost::asio和async_read,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6984571/