Эхо-сервер, созданный с помощью Netcat и FIFO, дает сбой при использовании с rev

Я играю с Netcat и успешно создал эхо-сервер, подобный этому:

mkfifo fifo
cat fifo | nc -l 3000 > fifo

Затем я хотел бы применить некоторое преобразование к данным, прежде чем они будут отражены:

cat fifo | nc -l 3000 | rev > fifo
# Or:
cat fifo | rev | nc -l 3000 > fifo

Но ни один из вышеперечисленных не работает. То же самое происходит, когда я использую любую программу преобразования текста, а не только rev. Но если я заменю rev на cat, он снова сработает:

cat fifo | nc -l 3000 | cat > fifo

Это наводит меня на мысль, что есть что-то особенное в том, как cat использует стандартный вход и стандартный выход. (По сравнению с rev, tr и другими подобными программами для преобразования текста.)

Что тут происходит? Почему вставка rev в конвейер ломает эхо-сервер? Действительно ли cat особенный, и если да, то как?


person rlkw1024    schedule 16.05.2014    source источник
comment
rev не может работать с потоками напрямую из-за его природы, если только он не создает копию всего файла в памяти на лету, а затем читает его с конца.   -  person technosaurus    schedule 17.05.2014
comment
Это не ответ, но хочется увидеть что-нибудь интересное: nc -l 3000 ‹ fifo | bash › fifo 2›&1 . это работает как псевдо телнет :)   -  person Tiago Lopo    schedule 17.05.2014


Ответы (1)


Это связано с буферизацией. glibc автоматически буферизует вывод, когда стандартный вывод не является терминалом. эффективность.

Вы можете увидеть тот же эффект в своем терминале, где rev переворачивает каждую строку по мере ее ввода, а rev | cat — нет.

Чтобы исправить это, вы должны заставить свою команду не буферизоваться. В GNU есть инструмент stdbuf для выполнения этого для произвольных команд:

cat fifo | nc -l 3000 | stdbuf -o 0 rev > fifo

Инструмент создания интерактивных командных сценариев expect также поставляется с командой unbuffer, позволяющей делать то же самое.

Буферизация эффективна только при объединении нескольких небольших операций записи в одну большую. Программы, которые просто копируют из одного места в другое (например, cat и dd), не получают выгоды от буферизации и поэтому не делают этого.

person that other guy    schedule 16.05.2014
comment
Читая stdbuf, я вижу, что cat действительно особенный. Но даже в этом случае, почему rev никогда не обрабатывает свой входной буфер и не сбрасывает его в fifo? Насколько я могу судить, в потоке, который я ему подаю, есть новые строки. Разве каждая полная линия не должна проходить через всю трубу? - person rlkw1024; 17.05.2014
comment
Это так, но вы должны ввести достаточно данных. В моей системе Ubuntu буфер rev составляет 4 КБ. Буферизация строк используется только тогда, когда стандартный вывод является терминалом, что здесь не так. - person that other guy; 17.05.2014
comment
Ах! Я неправильно понял. Я думал, вы говорите, что rev вообще не буферизуется. Когда на самом деле проблема в том, что это так; буфер просто больше, чем мне нужно. То, что я хочу, это буферизация строк. Имеет смысл. - person rlkw1024; 17.05.2014