2014-05-12 23 views
5

chcę zrobić asynchronicznego odczytu z cin dlatego mam kawałek koduStrange rzut wyjątek - przypisanie: Operacja niedozwolona

client.h

... 
boost::asio::posix::stream_descriptor input; 
boost::asio::streambuf input_buffer 

client.cpp

Client::Client(int argc, char **argv, boost::asio::io_service &io_service) 
    : tcp_socket(io_service) 
    , udp_socket(io_service) 
    , input(io_service, ::dup(STDIN_FILENO)) 
{ 
    ... 
    read_std_input(); 
} 

void Client::read_std_input() { 
    async_read_until(input, input_buffer, '\n', 
        boost::bind(&Client::handle_std_read, this, 
           boost::asio::placeholders::error, 
           boost::asio::placeholders::bytes_transferred)); 
} 

Problem polega na tym, że kiedy uruchamiam mojego klienta w normalny sposób [./client], a następnie wprowadzam coś za pomocą polecenia, to działa jak urok. Jednak, kiedy go uruchomić poprzez [./client < test] rzuca:

terminate nazywany po wrzuceniu wystąpienie 'boost :: exception_detail :: clone_impl

' co() : przypisanie: Operacja niedozwolona Przerwano

Czy masz pomysł, co może być problem? Dzięki!

+2

Nie wspomniano o platformie, z której korzystasz. Obsługa asynchronicznych operacji wejścia/wyjścia plików jest bardzo różna w systemach Windows i Linux (i ...). –

+0

im przy użyciu linuksa miętowego 16 64bit – darenn

+0

Spójrz na strace, aby zobaczyć, co może narzekać system operacyjny. – sehe

Odpowiedz

9

Boost.Asio POSIX-owe deskryptory strumieniowe jawnie nie obsługują zwykłych plików. Dlatego jeśli test jest zwykłym plikiem, wówczas ./client < test spowoduje niepowodzenie posix::stream_descriptor::assign() przy próbie przypisania STDIN_FILENO do stream_descriptor. W documentation stany:

Boost.Asio obejmuje zajęcia dodawane w celu umożliwienia synchronicznych i asynchronicznych operacji odczytu i zapisu wykonywanych na deskryptorów POSIX, takich jak rury, standardowe wejście i wyjście, a różnymi urządzeniami (ale nie zwykłe pliki).

Rozważ przekazanie zawartości pliku test do client przez rurę.

$ cat test | ./client 

Powyżej znajduje się pełna przykładowy program i demonstracji:

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

Demonstracja

 
$ ./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

Wielkie dzięki, wyjaśnia wszystko! – darenn

0

Czy możesz spróbować z tym minimalnym reproduktorem? To działa na moim Ubuntu 64-bitowym polu:

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

Aktualizacja myślę, że mogę odtworzyć problem on Coliru: można sprawdzić wyjście ulimit -a?

+0

ten kod również wyrzuca podczas przesyłania pliku do i/o. tutaj jest wyjście z ulimit -a: http://pastebin.com/WfpNkGjV – darenn

1

doładowania ASIO na Linuksie, wykorzystuje System epollby default który does not support files.

Ale istnieje obejście: jeśli zdefiniujesz BOOST_ASIO_DISABLE_EPOLL, wówczas asio powróci do systemu select, a pliki będą działać.

Powiązane problemy