BASH: Fifo 문제 - 입력에 대해 선별적인 것 같습니다.

BASH: Fifo 문제 - 입력에 대해 선별적인 것 같습니다.

그래서 나는 꽤 오랫동안 작업해온 데비안 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

어떤 이유로 파이프에 쓸 수 있는 사람(또는 적어도 쓸 수 있는 사람인 것처럼 보이는 사람)을 선택적으로 선택하기 시작합니다. 오류는 보이지 않지만 파이프에 텍스트를 보내려고 시도했지만 서버 측에서는 아무 일도 일어나지 않습니다.

이전에 프로그램이 작동했지만 동일한 프로그램이 작동하지 않는 경우 환경이 변경되었는지 확인하세요.

이러한 증상은 파이프에 여러 판독기가 있고 그 중 하나만 관찰하는 것과 일치합니다. 여러 프로세스가 파이프에서 데이터를 읽으면 데이터가 모든 프로세스로 전송될 수 있습니다.

고정된 이름을 가진 명명된 파이프를 사용하고 있습니다. 프로그램 어딘가에 리더 섹션의 잘못된 인스턴스가 있을 가능성이 높습니다.

명명된 파이프가 열려 있는 프로세스를 확인할 수 있습니다 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

관련 정보