简体   繁体   中英

boost::asio::async_read keeps returning eof on named pipe

Here is my sample code that opens a pipe in read mode. It uses boost::asio to read from the pipe. When data (let's say X bytes) is written to the pipe, it calls on_read with ec=EOF , bytes=X and X bytes of data in the buffer.

EOF is sent because the writer, after finishing writing to the pipe, closes it. I want to keep reading. That is why I call pipe.async_wait() in on_read . However, even if nothing is ready to be read from the pipe, on_read calls my_pipe::async_read() which again calls on_read() with bytes = 0 and ec=EOF . This goes on in an infinite loop.

Why does it keeping reading EOF repeatedly?

#include <boost/asio/io_service.hpp>
#include <boost/asio/placeholders.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <unistd.h>
#include <chrono>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <string>
#include <boost/asio/read.hpp>
#include <boost/asio/write.hpp>
#include <boost/bind.hpp>


class my_pipe final
{
public:
    explicit my_pipe(boost::asio::io_service& io_service);
    ~my_pipe();
private:
    boost::asio::posix::stream_descriptor pipe;
    std::vector<char> _buf{};
    void async_read(const boost::system::error_code& ec);
    void on_read(const boost::system::error_code& ec, std::size_t bytes_transferred);
};

my_pipe::my_pipe(boost::asio::io_service& io_service) : pipe(io_service)
{
    int fd = open("/tmp/pipe1", O_RDONLY | O_NONBLOCK);
    if (fd == -1)
        return;

    _buf.resize(8192);
    pipe.assign(fd);
    pipe.async_wait(boost::asio::posix::stream_descriptor::wait_read,
        boost::bind(&my_pipe::async_read, this, boost::asio::placeholders::error));
}

my_pipe::~my_pipe()
{
    pipe.close();
}

void my_pipe::async_read(const boost::system::error_code& ec)
{
    std::cout << "async_read\n";
    if (ec)
        return;
    boost::asio::async_read(pipe, boost::asio::buffer(_buf),
        boost::bind(&my_pipe::on_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void my_pipe::on_read(const boost::system::error_code& ec, std::size_t bytes)
{
    std::cout << "on_read. bytes=" << bytes << "\n";
    if (!ec || ec == boost::asio::error::eof) {
        if (ec == boost::asio::error::eof)
            std::cout << "eof\n";
        std::cout << "call async_read\n";
        pipe.async_wait(boost::asio::posix::stream_descriptor::wait_read,
            boost::bind(&my_pipe::async_read, this, boost::asio::placeholders::error));
    } else {
        std::cout << "on_read error: " << ec.message() << "\n";
    }
}

int main()
{
    boost::asio::io_service ios;
    my_pipe obj(ios);
    ios.run();
}

Thanks for all your help.

A pipe is "widowed" when all handles on one end are closed.

In this case, after you get an EOF, you should close the pipe handle and then reopen the pipe. You can then issue an async_read() on the new descriptor to wait for more data.

If you have multiple writers, also consider that writes are only guaranteed to be atomic up to PIPE_BUF bytes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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