Есть ли способ настроить канал Linux на небуферизацию или буферизацию строки? - PullRequest
3 голосов
/ 27 ноября 2011

Моя программа управляет внешним приложением в Linux, передает входные команды по каналу в stdin внешних приложений и считывает результаты вывода по каналу из stdout внешних приложений.

Проблема в том, что записи в каналы буферизуются по блокам, а не по строкам, и поэтому возникают задержки, прежде чем мое приложение получит данные, выводимые внешним приложением. Внешнее приложение нельзя изменить, чтобы добавить явные вызовы fflush ().

Когда я устанавливаю внешнее приложение на / bin / cat -n (оно возвращает вход, с добавленными номерами строк), оно работает правильно, кажется, cat сбрасывает после каждой строки. Единственный способ принудительно сбросить внешнее приложение - это отправить ему команду exit ; как только он получает команду, он сбрасывается, и все ответы появляются на стандартном выводе непосредственно перед выходом.

Я почти уверен, что каналы Unix являются подходящим решением для такого межпроцессного взаимодействия (псевдосервер-клиент), но, возможно, я ошибаюсь.

(Я только что скопировал текст из аналогичного вопроса: Принудительно небуферизовать стандартный вывод другой программы с помощью Python )

Ответы [ 4 ]

5 голосов
/ 27 ноября 2011

Не используйте трубу. Вместо этого используйте pty. Pty's (pseudo-ttys) имеет преимущество, заключающееся в возможности буферизации строки, если вы этого хотите, что обеспечивает простое кадрирование для вашего потока данных.

2 голосов
/ 28 ноября 2011

Использование PTY может быть избыточным решением для рассматриваемой проблемы (хотя будет работать ).

Если «целевое приложение» (утилита командной строки Delphi) динамическивозможно, гораздо более простое решение - вставить (через LD_PRELOAD) небольшую библиотеку в приложение.Эта библиотека просто должна реализовать isatty и ответить true (возврат 1) независимо от того, идет ли вывод в канал или на терминал.Возможно, вы захотите сделать это для всех файловых дескрипторов или только для STDOUT_FILENO.

Большинство реализаций UNIX будут вызывать isatty, чтобы решить, делать ли полную буферизацию или буферизацию строки для данного файлового дескриптора.

Хммм, glibc нет.Он вызывает __fxstat, а затем вызывает isatty, только если состояние указывает, что fd идет на символьное устройство.Так что вам нужно будет вставить и __fxstat, и isatty.Подробнее о вставке библиотеки здесь .

1 голос
/ 27 ноября 2011

По умолчанию стандартный ввод и стандартный вывод полностью буферизуются, если они не подключены к интерактивному устройству, в этом случае они имеют линейную буферизацию [1].Трубы не являются интерактивными устройствами.PTY являются интерактивными устройствами.«Полностью буферизованный» означает «использовать кусок памяти определенного размера».

Я уверен, что вы хотите буферизацию строки.Поэтому использование главного / подчиненного PTY вместо каналов должно автоматически переводить контролируемое приложение в правильный режим буферизации.

[1], см. Подробности в "stdin (3)" и "setbuf (3)".

0 голосов
/ 27 ноября 2011

Почему вызов fflush соответственно (на стороне записи) не работает для вас?

Вы можете использовать poll (или другие системные вызовы, такие как ppoll, pselect, select), чтобы проверить доступность ввода на стороне чтения.

Есливнешнее приложение использует <stdio.h> без соответствующего вызова fflush (возможно, с помощью setbuf, чтобы это произошло на новых строках ....), данные остаются в буфере FILE* даже без отправки (с writesyscall) к каналу!

Приложение может определить, является ли его вывод терминалом, например, isatty .Но это должно гарантировать, что промывка произойдет ...

Как предположил Майкл Диллон, использование pty -s, вероятно, является лучшим.Но это трудно (я забыл кровавые подробности).

...