Необходимо объяснить поведение чтения и именованного канала - PullRequest
0 голосов
/ 24 ноября 2018

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

Для многострочных ответов я попытался использовать цикл while в клиенте, чтобы продолжить чтение изтруба, я использовал что-то вроде этого:

read response < $id.pipe
while [ $response != "end_result" ]; do
    echo $response
    read response < $id.pipe

Это иногда возвращало бы полный результат, в других случаях возвращало бы его часть, а иногда нет.Когда он не вернул полный результат, я думаю, что выполняющийся скрипт был заблокирован каналом, поскольку операторы отладки показали, что он не выполнил свои последние строки.

Вместо этого я исправил это

tail <$return_pipe &

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

Если кому-то интересно, серверный скрипт вызывает скрипт так:

return_pipe=${ar[4]}.pipe
./select.sh ${ar[1]} ${ar[2]} ${ar[3]} >$return_pipe &

И часть сценария select, возвращающая результат, выглядит следующим образом:

echo "start_result"
cut -d' ' -f$3 ./$1/$2
echo "end_result"

Если кто-нибудь может помочь мне понять это и объяснить это, то это будет очень признательно.Это мой первый пост, поэтому я надеюсь, что отформатировал его тоже!Спасибо

1 Ответ

0 голосов
/ 24 ноября 2018

Это происходит потому, что fifo не ориентирован на пакеты.Это поток.

Это означает, что множественные записи могут объединяться в памяти, а закрытие канала без чтения всего буфера канала отбрасывает оставшуюся часть.Будет ли это происходить - это состояние гонки.Вот порядок событий, который работает:

  • Сервер открывает fifo для msg1
  • Клиент открывает fifo для msg1
  • Сервер пишет msg1
  • Сервер закрывает fifo
  • Клиент читает msg1
  • Клиент закрывает fifo
  • Выше повторяется в том же порядке для msg2

Вот пример кода со сном, чтобы обеспечить хороший порядок:

rm fifo; mkfifo fifo
{
  echo "hello" > fifo
  sleep 1
  echo "world" > fifo
} &

for i in 1 2
do
  echo "Reading..."
  { read var; } < fifo
  sleep 1
  echo "Read: $var"
done

Это выведет то, что вы ожидаете:

Reading...
Read: hello
Reading...
Read: world

Вот порядок событий, который не удается:

  • Сервер открывает fifo для msg1
  • Клиент открывает fifo для msg1
  • Сервер записывает msg1 и закрывает fifo
  • Сервер открывает fifo для msg2
  • Сервер записывает msg2 и закрывает fifo
  • Клиент читает msg1
  • Клиент закрывает fifo, пока msg2 еще не прочитана.msg2 теперь потеряно.

Вот несколько снов, чтобы это произошло:

rm fifo; mkfifo fifo
{
  echo "hello" > fifo
  echo "world" > fifo
} &

for i in 1 2
do
  echo "Reading..."
  { sleep 1; read var; } < fifo
  echo "Read: $var"
done

Теперь он напечатает:

Reading...
Read: hello
Reading...

и зависнет, потому что world было потеряно.

Вместо этого вы должны были открыть fifo один раз с обоих клиентов сервера и продолжать запись в один и тот же открытый FD.Это обеспечило бы бесперебойную и эффективную связь без потери данных.

...