BASH: лучшая архитектура для чтения из двух входных потоков - PullRequest
5 голосов
/ 15 июля 2011

Простой скрипт здесь:

a) постоянно считывает данные из сокета и сохраняет значения в ассоциативном массиве
b) постоянно считывать значения из stdin и отвечать t / f, если они уже существуют в ассоциативном массиве

a & b - случайные события, никак не связанные.

Хитрость заключается в доступе к массиву из обоих подпроцессов (поскольку помещение процесса в фоновом режиме порождает его как подпроцесс)

Я обдумываю лучшую стратегию, и возникает несколько идей, но мне интересно, есть ли у кого-нибудь что-нибудь лучше:

1) перенаправить ввод из сокета в stdin в качестве подпроцесса и обработать оба ввода в одном цикле while (размеры данных невелики, <30 символов, поэтому я предполагаю, что они останутся атомарными?). <br> 2) прочитать сокет, затем STDIN с небольшими (0,1?) Значениями тайм-аута при чтении, чтобы имитировать неблокирующий ввод / вывод.
3) ОБНОВЛЕНИЕ: записать данные сокета в файл (фактически, другой процесс записывает их непосредственно в файл), затем каждый раз, когда приходит запрос, чтобы проверить, существует ли значение, обрабатывают записи в файл, добавив их в массив (используйте блокировку файла).

Ответы [ 2 ]

4 голосов
/ 15 июля 2011

Bash не подходит для этого.Эта проблема обычно решается с помощью системных вызовов select(2) или poll(2), которые позволяют одновременно ожидать несколько дескрипторов файлов без вращения.Bash не имеет интерфейса ни к одному из них.

Я бы порекомендовал использовать язык сценариев, такой как Python или Perl (как вам удобно, на самом деле), который обеспечивает интерфейс с select или poll (например, модуль Python select).

3 голосов
/ 15 июля 2011

Не знаю, является ли это полностью практичным и достаточно атомарным в описанном контексте, но используя модель клиент / сервер и именованные каналы, можно создать цикл while, который может различать строки, идущие от fifo или stdin.

Сервер постоянно читает строки из сокета (/tmp/to), а также строки из stdin (который перенаправляется на сервер через /tmp/to).

Однако строки из stdin помечаются байтом del (\177) как первый байт строки.

Затем (фоновый) клиентский цикл while использует этот первый байт строки для различения строк различного происхождения.

# terminal window 1

# server
(
rm -f /tmp/to /tmp/from
mkfifo /tmp/to /tmp/from
while true; do 
  while IFS="" read -r -d $'\n' line; do 
    printf '%s\n' "${line}"
  done </tmp/to >/tmp/from &
  bgpid=$!
  exec 3>/tmp/to
  exec 4</tmp/from
  trap "kill -TERM $bgpid; exit" 0 1 2 3 13 15
  wait "$bgpid"
  echo "restarting..."
done
) &
serverpid=$!

# client
(
exec 3>/tmp/to;
exec 4</tmp/from;
while IFS="" read -r -d $'\n' <&4 line; do
  if [[ "${line:0:1}" == $'\177' ]]; then 
    printf 'line from stdin: %s\n' "${line:1}"
  else       
    printf 'line from fifo: %s\n' "$line"
  fi
done &
trap "kill -TERM $"'!; exit' 1 2 3 13 15
while IFS="" read -r -d $'\n' line; do
  # can we make it atomic?
  # sleep 0.5
  # dd if=/tmp/to iflag=nonblock of=/dev/null  # flush fifo
  printf '\177%s\n' "${line}"
done >&3
) 
#kill -TERM $serverpid


# terminal window 2
echo hello > /tmp/to
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...