BASH:Fifoの問題 - 入力に対してスクリーニングのようです。

BASH:Fifoの問題 - 入力に対してスクリーニングのようです。

だから私はかなり長い間働いてきたDebian 7のBASHサービスに問題があり、そのFIFOがランダムに問題を引き起こし始めているようです。これは古典的なfifoの使用例に基づいており、数ヶ月間うまく機能しましたが、今日は突然問題が発生し始めました。このようなことが起こるたびに、最初に下した結論とはいつもまったく違うようで、私が持っていることを見せてくれる。

私が言ったように、名前付きパイプで読み書きするコードはかなり標準的です。簡単なバージョン(150行程度)を作ってお見せしなければならないと思いましたが、もちろんうまく動作するのに理由はわかりません。参照用に要約されたバージョンは次のとおりです。

#--------------------------------Writer Script--------------------------------------#
#!/bin/bash

fifoIn=".../path/fifoIn"

#Read user input
IFS='' #Changed IFS so that spaces aren't trimmed from input
while true; do
    read -e line
    printf "%b\n" "$line" >&4
done 4>"$fifoIn"

exit 0

#--------------------------------Reader Script--------------------------------------#
#!/bin/bash

fifoIn=".../path/fifoIn"
LogFile=".../path/srvc.log"
[ -d ".../path" ] || mkdir -p ".../path"
[ -e "$fifoIn" ] || mkfifo "$fifoIn"

printf "%b\n" "Flushing input pipe" >> "$LogFile"
dd if="$fifoIn" iflag=nonblock of=/dev/null >/dev/null 2>&1

while true; do
    if read -t 0.1 -a str; then
        printf "\n%s\n" "<${str[*]}>"
        case "${str[0]}" in
            "foo")
                printf '%b\n' "You said foo..."
                ;;
            "bar")
                printf '%b\n' "You said bar..."
                ;;
            "")
                ;;
            *)
                printf "%b\n" "${str[*]}:"
                printf "%b\n" "Uhhuh..."
                ;;
        esac
    fi
done <"$fifoIn" >> "$LogFile" 2>&1 3>"$fifoIn"

echoしたがって、「リーダースクリプト」をインポートしてデーモンとして実行し、ingまたはingを介して会話するか、ビルダーprintfスクリプトを使用して名前付きパイプにメッセージを送信しますfifoIn。これは最初からうまくいきましたが、今日は奇妙になりました。

何らかの理由でパイプに書き込むことができる人(または少なくとも書くことができる人のように見える人)を選択的に選択し始めます。エラーは見えませんが、パイプにテキストを送信しようとしましたが、サーバー側では何も起こりません。私はパイプに書き込むためにcronジョブを設定しましたが、問題なく動作し、echo端末では何も得られません。エラーや権限拒否メッセージもありません。とにかく、クローンの操作は私の端末と同じユーザーに設定されているので、権限の問題ではないようです。

FIFOを削除してサービスを再起動するたびに、通常は一部の端末入力メッセージを受信できるように見えますが、必ずしもそうではありません。 cronが開始したメッセージがサービスジョブに送信された後、ブロックまたは停止されるようです。提供する。もはやパイプを介してメッセージを送信することはできませんが、クローンで始まったメッセージは引き続き正常に流れます!

インターネット検索をしてこのstraceコマンドを見つけました。私は似たようなことを試してみましたが、strace printf '%b\n' "foo" >> .../path/fifoIn私はよく理解していない診断システム呼び出しをたくさん受けましたが、そのようなことがなかったので、すべてがうまくいくように見え、最終的に次のようにHey! right here! something broke right here!!なりました。

...
write(1, "foo\n", 4)
close(1)
...

どうやらいいことだと思います。興味深いのは、メッセージが配信され、デーモンが期待どおりにメッセージを読み取ることです。私はその行を削除し、strace再びサイコロがありません。

それでは、私よりもio演算とシステムコールについてもっと知っている皆さんにstrace序文がある時とない時はどうなりますか?読むためにパイプを閉じずに、パイプに通常何が付着しますか?私が言うことを失ったので、あなたが見つけることができる他の手がかりがあるかもしれません。

修正する

@Gilles、私の考えでは、別のプロセスが同じパイプを読み取ろうとして問題を引き起こしていることを示唆しているようです。fifoIn何らかの理由で関連しているように見えるいくつかのmuttインスタンスを呼び出す新しい関数を作成しました。出力をどのように読み取るかはわかりませんがlsof、関数を実行した後、次のように読みます(したがってパイプがめちゃくちゃになります)。

COMMAND     PID   TID        USER   FD      TYPE DEVICE SIZE/OFF     NODE NAME
mutt      13874           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13874           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13897           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13897           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13932           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13932           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13971           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      13971           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14012           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14012           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14051           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14051           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14096           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14096           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14124           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
mutt      14124           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
srvc      14298           uname    0r     FIFO   8,17      0t0   393222 .../path/fifoIn
srvc      14298           uname    3w     FIFO   8,17      0t0   393222 .../path/fifoIn
lsof      15587           uname    1w     FIFO    0,8      0t0   176516 pipe
lsof      15587           uname    5w     FIFO    0,8      0t0   176524 pipe
lsof      15587           uname    6r     FIFO    0,8      0t0   176525 pipe
grep      15588           uname    0r     FIFO    0,8      0t0   176516 pipe
lsof      15589           uname    4r     FIFO    0,8      0t0   176524 pipe
lsof      15589           uname    7w     FIFO    0,8      0t0   176525 pipe

私は誤ってmutt呼び出しを書いたようです(最終的にはサブシェルで実行されます)。コマンドに問題があり、継承されたFDがロックされました。私はそれが答えだと言い、そこからそれを取るでしょう! 「回答」を投稿して喜んでお選びいたします!

ベストアンサー1

何らかの理由でパイプに書き込むことができる人(または少なくとも書くことができる人のように見える人)を選択的に選択し始めます。エラーは見えませんが、パイプにテキストを送信しようとしましたが、サーバー側では何も起こりません。

以前にプログラムが機能していたが同じプログラムが機能しない場合は、環境が変更されていることを確認してください。

これらの症状は、パイプに複数のリーダーがあり、そのうちの1つだけを観察することと一致します。複数のプロセスがパイプからデータを読み取ると、データがすべてのプロセスに転送される可能性があります。

固定名の名前付きパイプを使用しています。プログラムのどこかにリーダーセクションの無効なインスタンスがある可能性があります。

名前付きパイプが開いているプロセスを確認できますlsof

lsof .../path/fifoIn

パイプにライターがないと、open呼び出し時にリーダーがブロックされる可能性があります。名前付きパイプを開くと、ライターが表示されるまでブロックされます。lsofパイプがまだ開いていないため、これらの内容は報告されません。open通話でブロックされたプロセスを見つける方法がわかりません。open書き込みのために呼び出しを開いて、すべてのプロセスで呼び出しを返すことができます。

sleep 99999999 >.../path/fifoIn &
lsof .../path/fifoIn

開いたファイルは子プロセスによって継承されることを覚えておいてください。パイプが開いている間にプログラムがバックグラウンドで別のプログラムを起動すると、そのプログラムはまだ読み取るためにパイプを開いたままにすることができます。パイプを閉じたいと思うかもしれません。

while … do
  subprocess_that_does_not_need_the_pipe </dev/null
done <.../path/fifoIn

または

while … do
  subprocess_that_does_not_need_the_pipe 0<&3
done 3<&0 <.../path/fifoIn

おすすめ記事