Ловушка SIGPIPE при попытке записи без читателя

Я пытаюсь реализовать коммуникацию по именованным каналам между двумя процессами в Bash.

Первый процесс записывает что-то в именованный канал:

send(){
    echo 'something' > $NAMEDPIPE
}

И второй сценарий должен читать именованный канал следующим образом:

while true;do
  if read line < $NAMEDPIPE;do
      someCommands
  fi
done

Обратите внимание, что именованный канал был ранее создан с использованием традиционной команды

mkfifo $NAMEDPIPE

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

Я хочу избежать этого поведения, и решение было бы перехватить сигнал SIGPIPE. Действительно, согласно человеку 7, сигнал должен отправляться при попытке записи в канале без считывателя. Так что я изменил свою красную функцию:

read(){
    trap 'echo "SIGPIPE received"' SIGPIPE
    echo 'something' > $NAMEDPIPE
}

Но когда я запускаю скрипт считывателя, он остается заблокированным, и "SIGPIPE полученный" не печатается.

Я ошибаюсь в сигнальном механизме или есть лучшее решение моей проблемы?

1 ответ

Решение

Вот забавный код, который я только что сделал. Возможно, вы можете сослаться на это:

#!/bin/bash

shopt -s extglob

NAMEDPIPE=/var/run/sr-pipe
RECEIVER_PID_FILE=/var/run/sr-receiver-pid

function sender_start {
    # Create named pipe.

    if [[ -e $NAMEDPIPE ]]; then
        echo "[Sender] Named pipe \"$NAMEDPIPE\" already exists."
    else
        echo "[Sender] Creating named pipe \"$NAMEDPIPE\"."
        mkfifo "$NAMEDPIPE" || {
            echo "Failed to create named pipe \"$NAMEDPIPE\"."
            exit 1
        }
    fi

    # Wait for receiver.

    echo "[Sender] Waiting for receiver."
    local PID
    until [[ -e $RECEIVER_PID_FILE ]] \
    && read PID < "$RECEIVER_PID_FILE" \
    && [[ $PID == +([[:digit:]]) ]] \
    && kill -s 0 "$PID" &>/dev/null; do
        sleep 1s
    done
    echo "[Sender] Receiver is [now] active."

    # Send signal.

    kill -s SIGPIPE "$PID"

    # Send messages.

    local SEND=''

    echo "[Sender] Now sending messages."
    while sleep 1s; do
        SEND=$RANDOM
        echo "[Sender] Sending $SEND."
        echo "$SEND" >&4
    done 4>"$NAMEDPIPE"
}

function receiver_start {
    echo "$BASHPID" > "$RECEIVER_PID_FILE"

    echo "[Receiver] Receiver is now active."

    local QUIT=false RECEIVE=false

    trap 'RECEIVE=true' SIGPIPE
    trap 'QUIT=true' SIGINT SIGTERM SIGHUP

    while [[ $QUIT == false ]]; do
        if [[ $RECEIVE == true ]]; then
            RECEIVE=false
            echo "[Receiver] Now receiving messages."
            while [[ $QUIT == false ]] && IFS= read -r -u 4 LINE; do
                echo "[Receiver] Received $LINE."
            done 4<"$NAMEDPIPE"
        fi
        sleep 1s
    done
}

if [[ $1 == send ]]; then
    sender_start
elif [[ $1 == receive ]]; then
    receiver_start
fi

На одном терминале я запустил это:

# bash sender-receiver.sh send
[Sender] Named pipe "/var/run/sr-pipe" already exists.
[Sender] Waiting for receiver.
[Sender] Receiver is [now] active.
[Sender] Now sending messages.
[Sender] Sending 21524.
[Sender] Sending 1460.
[Sender] Sending 8352.
[Sender] Sending 4424.
...

А по другому я получил (исправил):

# bash sender-receiver.sh receive
[Receiver] Receiver is now active.
[Receiver] Now receiving messages.
[Receiver] Received 21524.
[Receiver] Received 1460.
[Receiver] Received 8352.
[Receiver] Received 4424.
...

Вы, вероятно, можете запустить отправителя на заднем плане и получателя на переднем плане на одном терминале.

Другие вопросы по тегам