我正在尝试侦听命名管道上的输入。我在Linux下使用Boost.Asio的stream_descriptor和async_read。问题是,对io_service :: run()的调用仅阻止我想要它直到第一次读取。之后,即使我尝试将更多的async_reads附加到它,它仍然会立即使用“文件结束”错误调用处理程序。我的代码等同于以下内容:
boost::asio::io_service io_service;
int fifo_d = open("/tmp/fifo", O_RDONLY);
boost::asio::posix::stream_descriptor fifo(io_service, fifo_d);
while (true)
{
// buffer and handler probably aren't important for the purposes of this question
boost::asio::async_read(fifo, buffer, handler);
io_service.run();
}
只有第一个async_read按我的预期工作。后续的async_reads只是立即返回。我发现让它像我想要的那样工作的唯一方法是关闭并重新打开命名管道,但它似乎是一个黑客:
boost::asio::io_service io_service;
while (true)
{
int fifo_d = open("/tmp/fifo", O_RDONLY);
boost::asio::posix::stream_descriptor fifo(io_service, fifo_d);
boost::asio::async_read(fifo, buffer, handler);
io_service.run();
close(fifo_d);
}
谁能告诉我我做错了什么?
更新:这是一个简单的“读取”版本,允许一些代码简化,问题依然存在:
int fifo_d = open("/tmp/fifo", O_RDONLY);
boost::asio::posix::stream_descriptor fifo(io_service, fifo_d);
while (true) {
try {
boost::asio::read(fifo, boost::asio::buffer(buffer));
}
catch (boost::system::system_error& err) {
// It loops here with "read: End of file" error
std::cout << err.what() << std::endl;
}
}
答案 0 :(得分:1)
这不是多么有效。 run()
不打算在循环中调用。如果您坚持,则需要在两者之间调用reset()
(根据文档)。
此外,如果您/想要/阻止行为,为什么使用async_*
界面?
考虑使用简单的iostream来读取fd:
<强> Live On Coliru 强>
#include <iostream>
#include <fstream>
int main() {
std::ifstream fifo("/tmp/fifo");
std::string word;
size_t lineno = 0;
while (fifo >> word) {
std::cout << "word: " << ++lineno << "\t" << word << "\n";
}
}
或者,如果您必须附加到其他地方的fd
,请使用Boost IOstreams中的file_descriptor
:
<强> Live On Coliru 强>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream>
#include <fcntl.h>
int main() {
namespace io = boost::iostreams;
using src = io::file_descriptor_source;
io::stream<src> fifo(src(open("./fifo", O_RDONLY), io::file_descriptor_flags::close_handle));
std::string word;
size_t number = 0;
while (fifo >> word) {
std::cout << "word: " << ++number << "\t" << word << "\n";
}
}
两个示例都打印出预期的内容:
word: 1 hello
word: 2 world
答案 1 :(得分:0)
据报道,这不是boost :: asio的工作方式。
ioservice::run()
方法在阻塞模式下运行,但有一些工作。当ioservice失去工作时,你必须在进行其他工作之前调用reset()
方法,这就是为什么在你的第一个代码中async_read只执行一次。
这种情况下的常见模式如下:
void handler(...) {
if (!error) {
// do your work
boost::asio::async_read(fifo, buffer, handler); // <-- at the end of the handler a subsequent async_read is put to the ioservice, so it never goes out-of-work
}
}
boost::asio::io_service io_service;
int fifo_d = open("/tmp/fifo", O_RDONLY);
boost::asio::posix::stream_descriptor fifo(io_service, fifo_d);
boost::asio::async_read(fifo, buffer, handler); // <-- you call async_read only once here.
io_service.run(); //<-- this blocks till an error occurs