2011-07-15 3 views
5

Простого скрипта здесь:BASH: Лучшая архитектура для чтения из двух входных потоков

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

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

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

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

1) перенаправляют вход от розетки до стандартного ввода как подпроцесс и обрабатывать оба вход в один, а цикл (размеры данных невелики, < 30 символов, так что я предполагаю, что они будут оставаться атомными ?).
2) прочитайте разъем, затем STDIN с малыми значениями времени ожидания (0,1?) При чтении, чтобы имитировать неблокирующий ввод-вывод.
3) UPDATE: записать данные сокета в файл (фактически, другой процесс записывает его непосредственно в файл), то каждый раз, когда приходит запрос на проверку, существует ли это значение, обрабатывайте записи в файле, добавив их в массив (используйте блокировку файлов).

+0

Похоже, что у вас есть правильная идея. Есть ли причина сделать это в bash в отличие от другого языка? – Slartibartfast

+0

Хороший вопрос. Нет, нет веских оснований использовать bash над другим языком. Баш прост и мал, это единственная причина (и у меня есть еще 5 других сценариев bash, которые выполняют аналогичные задачи проверки подлинности/ведения журналов/пользователей, поэтому хорошо поддерживать единую платформу) –

ответ

4

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

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

+0

Спасибо, что установили меня прямо на этом.Ты прав. Посмотрев на это больше, и будучи java-парнем, я собираюсь собрать отличный и приложить усилия, чтобы выполнить эту задачу в отличном стиле. Это было в моем списке желаний, чтобы узнать какое-то время. –

2

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

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

Однако строки от stdin помечаются байтом del, чтобы быть первым байтом строки.

Затем (в фоновом режиме) клиентский цикл 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 
Смежные вопросы