Почему я получаю EOF после прочтения одной строки через именованный канал с помощью ifstream?

В командной строке я использовал mkfifo для создания канала и подтвердил, что файл существует. ls -al дает:

prw-r--r--    1 user  group      0 Mar 30 11:52 my_pipe

Затем я использую этот код, чтобы попытаться прочитать текст построчно из этого канала:

ifstream pipe("/path/to/my_pipe");
string message;
while(getline(pipe, message) && message != "EXIT")
{
    cout << boolalpha << pipe.good() << endl << pipe.eof() << endl << pipe.bad() << endl;
}

cout << boolalpha << pipe.good() << endl << pipe.eof() << endl << pipe.bad() << endl;

Вернувшись в командную строку, я делаю echo "banana" > my_pipe, а затем существует программа со следующим выводом:

true
false
false
false
true
false

Это будет означать, что поток был в хорошем состоянии после чтения banana, но что во втором вызове getline я нажал EOF и вышел.

Почему я нажал EOF и что я могу сделать, чтобы поток читался и находился в хорошем состоянии, пока я не прочитал свое специальное сообщение EXIT?

РЕДАКТИРОВАТЬ:

Выводы:

  1. Используйте fstream вместо ifstream.
  2. По-видимому, на момент написания этой статьи в libc ++ есть ошибка, касающаяся fstream и каналов.

person screwnut    schedule 30.03.2015    source источник


Ответы (1)


EOF возникает в канале, когда он закрыт всеми процессами, открытыми для записи. В вашем примере единственный процесс, который открывает его для записи, - это команда echo; когда он выходит, он закрывает канал, что приводит к EOF в процессе чтения.

Если вы хотите, чтобы канал оставался открытым между каждым клиентом, записывающим в него, способ сделать это - открыть канал в режиме чтения-записи. Таким образом, процесс чтения также будет процессом записи, и пока он имеет открытый канал, он никогда не будет закрыт всеми авторами.

fstream pipe("/path/to/my_pipe");

В качестве альтернативы вы можете оставить канал открытым на отправляющей стороне, выполнив несколько команд в одном перенаправленном процессе:

( echo banana ; echo EXIT ) > my_pipe
person Barmar    schedule 30.03.2015
comment
Я пробовал с простым fstream, но он просто никогда не возвращается с getline. Кстати, ios::in|ios::out - это режим по умолчанию для fstream, так что это вроде как избыточно. - person screwnut; 31.03.2015
comment
Он должен вернуться из getline, как только кто-нибудь напишет ему строку. А до тех пор следует просто подождать. Однако он никогда не выйдет из цикла. - person Barmar; 31.03.2015
comment
Я добавил ответ, который показывает, как держать канал открытым между командами эха. - person Barmar; 31.03.2015
comment
Да, он должен вернуться из getline, но этого не происходит. Подходит ли это вам? Это ошибка в моей реализации? Кроме того, я ожидаю, что эта программа будет долгоживущей, а не просто выполнением однократного прослушивания нескольких отраженных строк. - person screwnut; 31.03.2015
comment
Я только что это проверил. Я запустил программу в одном окне, затем перешел в другое окно и сделал echo foo > my_pipe. Первое окно напечатало true false false. - person Barmar; 31.03.2015
comment
Затем я сделал echo EXIT > my_pipe во втором окне, оно напечатало то же сообщение и закрылось. - person Barmar; 31.03.2015
comment
Хорошо, я могу сказать вам, что в MacOS (Apple LLVM версии 6.0 (clang-600.0.57)) getline не возвращается, если pipe является fstream. Он возвращается, если это ifstream, но тогда следующее чтение - EOF. Итак ... Похоже на ошибку в libstdc ++. Я полагаю, вы работаете в Linux? - person screwnut; 31.03.2015
comment
Да, я пробовал на Linux, у меня возникли проблемы с компиляцией тестовой программы на Snow Leopard. - person Barmar; 31.03.2015
comment
Окончательное подтверждение. Я попробовал тот же код на виртуальной машине Linux, и он вел себя так, как вы и предполагали. В MacOS он ведет себя так, как я описал. - person screwnut; 31.03.2015