简体   繁体   English

Boost.Asio - 轮询命名管道

[英]Boost.Asio - polling a named pipe

I am trying to listen for input on a named pipe. 我正在尝试在命名管道上侦听输入。 I'm using Boost.Asio's stream_descriptor and async_read under Linux. 我在Linux下使用Boost.Asio的stream_descriptorasync_read The problem is, the call to io_service::run() only blocks like I want it to until the first read. 问题是,对io_service :: run()的调用仅阻止我想要它直到第一次读取。 After that, it just keeps calling the handler immediately with the "End of file" error, even though I try to attach more async_reads to it. 之后,即使我尝试将更多的async_reads附加到它,它仍然会立即使用“文件结束”错误调用处理程序。 The code I have is equivalent to the following: 我的代码相当于以下内容:

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();
}

Only the first async_read works as I expect it to. 只有第一个async_read按预期工作。 Subsequent async_reads just return immediately. 后续的async_reads只是立即返回。 The only way I found to make it work like I want is to close and reopen the named pipe, but it seems like a hack: 我发现让它像我想要的那样工作的唯一方法是关闭并重新打开命名管道,但它似乎是一个黑客:

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

Can anyone tell me what am I doing wrong? 谁能告诉我我做错了什么?

UPDATE: Here's a simple "read" version, which allowed for some code simplification, the problem remains the same: 更新:这是一个简单的“读取”版本,允许一些代码简化,问题仍然是相同的:

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

This is not how works. 这不是多么有效。 run() is not intended to be called in a loop. run()不打算在循环中调用。 If you insist, you need to call reset() in between (as per the documentation). 如果你坚持,你需要在两者之间调用reset() (根据文档)。

Also, if you /want/ blocking behaviour, why are you using the async_* interface? 此外,如果您/想要/阻止行为,为什么使用async_*接口?

Demos 演示

  1. Consider using a simple iostream to read the fd: 考虑使用简单的iostream来读取fd:

    Live On Coliru 住在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"; } } 
  2. Or if you must attach to some fd you get from somewhere else, use file_descriptor from Boost IOstreams: 或者,如果您必须附加到其他地方的某个fd ,请使用Boost IOstreams中的file_descriptor

    Live On Coliru 住在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"; } } 

Both examples print the expected: 这两个例子打印出预期的:

word: 1 hello
word: 2 world

As also sehe reported, that's not the way boost::asio works. 正如sehe报道的那样,这不是boost :: asio的工作方式。 The ioservice::run() method runs in blocking mode while it has some work. ioservice::run()方法在阻塞模式下运行,但它有一些工作。 When the ioservice goes out of work you have to call the reset() method before putting other work, so that's why in your first code the async_read is done only once. 当ioservice失去工作时,你必须在调用其他工作之前调用reset()方法,这就是为什么在你的第一个代码中async_read只执行一次。

A common pattern in this case would look something like: 在这种情况下,常见的模式如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM