Strange exception throw - assign: Operation not permitted

前端 未结 4 1985
暗喜
暗喜 2020-12-03 19:18

I want to do asynchronous read from cin therefore I have a piece of code

client.h

...
boost::asio::posix::stream_descriptor input;
boost::asio::stre         


        
相关标签:
4条回答
  • 2020-12-03 19:51

    Boost.Asio's POSIX stream-oriented descriptors explicitly do not support regular files. Hence, if test is a regular file, then ./client < test will result in posix::stream_descriptor::assign() failing when attempting to assign STDIN_FILENO to the stream_descriptor. The documentation states:

    Boost.Asio includes classes added to permit synchronous and asynchronous read and write operations to be performed on POSIX file descriptors, such as pipes, standard input and output, and various devices (but not regular files).

    Consider passing the contents of the test file to client through a pipe.

    $ cat test | ./client
    

    Here is a complete example program and demonstration:

    #include <iostream>
    #include <boost/asio.hpp>
    
    void handle_read(
      const boost::system::error_code& error,
      std::size_t bytes_transferred
    )
    {
      std::cout << "read " << bytes_transferred << " bytes with "
                << error.message() << std::endl;
    }
    
    int main()
    {
      boost::asio::io_service io_service;
      boost::asio::posix::stream_descriptor input(io_service);
    
      // Assign STDIN_FILENO to the stream_descriptor.  It will support
      // pipes, standard input and output, and various devices, but NOT
      // regular files.
      boost::system::error_code error;
      input.assign(STDIN_FILENO, error);
      if (error)
      {
        std::cerr << error.message() << std::endl;
        return -1;
      }
    
      boost::asio::streambuf input_buffer;
      async_read_until(input, input_buffer, '\n', &handle_read);
      io_service.run();
    }
    

    Demonstration

    $ ./client
    testing standard inputenter
    read 23 bytes with Success
    $ echo "this is a test" > test
    $ ./client < test
    Operation not permitted
    $ cat test | ./client
    read 15 bytes with Success
    
    0 讨论(0)
  • 2020-12-03 19:58

    Can you try with this minimal reproducer? It works on my Ubuntu 64-bit box:

    #include <boost/asio.hpp>
    #include <boost/asio/posix/stream_descriptor.hpp>
    
    #include <iostream>
    
    int main()
    {
        using namespace boost::asio;
    
        io_service io;
        posix::stream_descriptor input(io);
    
        input.assign(STDIN_FILENO);
        streambuf input_buffer;
    
        std::function<void()> loop = [&] {
            async_read_until(input, input_buffer, '\n', [&](boost::system::error_code ec, size_t) {
                if (ec) 
                    std::cerr << ec.message();
                else {
                    std::cout << "LOOP: '" << &input_buffer << "'\n";
                    loop();
                }
            });
        };
    
        loop();
        io.run();
    }
    

    Update I think I can reproduce the problem on Coliru: can you check the output of ulimit -a?

    0 讨论(0)
  • 2020-12-03 20:03

    Asynchronous file I/O on Linux is still rather primitive. Although the ASIO support for asynchronous file I/O works well in Windows, I haven't had much (...er any) luck using it on Linux.

    This is a previous SO question that provides some background on the issue.

    0 讨论(0)
  • 2020-12-03 20:11

    Boost asio, on Linux, uses the epoll system by default which does not support files.

    But there's a workaround: if you define BOOST_ASIO_DISABLE_EPOLL then asio will revert to the select system and files will work.

    0 讨论(0)
提交回复
热议问题