Überprüfen Sie, ob die benannte Pipe zum Lesen geöffnet ist

Überprüfen Sie, ob die benannte Pipe zum Lesen geöffnet ist

Im Moment habe ich diese beschissene Prüfung, um zu sehen, ob aus einer benannten Pipe gelesen wird:

is_named_pipe_being_read() {

    local named_pipe="$1" 
    echo "unlocked" > "$named_pipe" & 
    pid="$!"
    # Wait a short amount of time
    sleep 0.25
    # Kill the background process. If kill succeeds, then
    # the write was blocked 
    ( kill -PIPE "$pid" ) &> /dev/null
}

Wenn das Kill funktioniert (mit 0 beendet wird), bedeutet dies, dass niemand aus der Pipe gelesen hat.

Aber anstatt eine Verzögerung von 0,25 Sekunden zu haben und einen unnötigen Prozess zu starten, suche ich nach einer Möglichkeit, die benannte Pipe zu überprüfen, um festzustellen, ob sie zum Lesen geöffnet ist. Gibt es eine Möglichkeit, festzustellen, ob etwas daraus liest?

Notiz: Ich kann bei diesem Aufruf nicht aus der Pipe lesen, ich kann nur in sie schreiben (weil bei benannten Pipes die Reihenfolge, in der Leser angeschlossen werden, nicht eingehalten zu werden scheint – oder vielleicht erhält der neueste Leser die Daten, nicht der älteste Leser).

Antwort1

if /bin/echo unlocked 1<>fifo >fifo; then
    there are readers
else
    no there ain\'t
fi

is_named_pipe_being_read(){ /bin/echo unlocked 1<>"$1" >"$1"; }

Der /bin/echowird durch einen beendet SIGPIPEund gibt einen Status ungleich Null zurück, wenn keine Leser vorhanden sind.

Sie können das integrierte Feature nicht verwenden echo(auch nicht in einer Untershell), da es SIGPIPEentweder abgefangen wird oder die gesamte Shell beendet.

Genau wie die Version aus dem OP ist dies destruktiv. Wenn Sie GNU dd haben, können Sie einfach versuchen, die Datei mit zu öffnen O_NONBLOCK, wie von C:

is_named_pipe_being_read(){ dd oflag=nonblock conv=notrunc,nocreat count=0 of="$1" 2>/dev/null; }

Aber das ist nicht viel besser; wenn es andere Schreiber in der Pipe gibt, führt das automatische Schließen des FIFO beim Befehlsausgang dazu, dass alle Leser ein EOF erhalten.

Notiz:Die Verwendung benannter Pipes ist eher eine Frage des Masochismus oder der Standardpedantik [1]. Die BSD-Sockets-API, wie sie von den Unix-Domain-Sockets implementiert wird, ist unvergleichlich besser (deshalb beherrscht sie die Welt ;-)), und es gibt Programme wie die neueren Versionen, die netcatsie auch von der Shell aus einigermaßen nutzbar machen.

[1] was in Beispielen wie dem obigen widerlegt wird oderDasdurch die Tatsache, dass das Öffnen eines FIFO im RW-Modus laut Standard „undefiniert“ ist, obwohl es in den meisten Systemen seit etwa 30 Jahren genauso implementiert ist)).

Antwort2

Ich habe dieses C-Programm gestohlen vonhttps://stackoverflow.com/a/20694422/5047085:

#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#include <sys/stat.h>

#define SERVFIFO "/Users/alex/.locking/ql/locks/a/fifo.lock"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

void syserr(const char *str){
    perror(str);
    exit(1);
}

int main(int argc, char** argv){

    umask(0);

    // try to open for write with no readers

    int fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);

    if (fdw == -1){
      syserr("non-blocking open for write with no readers failed");
    }

    // create a reader - the process itself - non-blocking

    int fdr = open(SERVFIFO, O_RDONLY | O_NONBLOCK);
    if (fdr == -1){
      syserr("non-blocking open for read no writers failed");
    }

    // try again to open for write but this time with a reader
    fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);

    if (fdw == -1){
      syserr("non-blocking open with readers failed");
    }


    printf("non-blocking open for write succeeded\n");

    close(fdw);
    close(fdr);

}

Wenn es mit 0 beendet wird, bedeutet das, dass bereits jemand aus der benannten Pipe liest. Und wenn es mit 1 beendet wird, bedeutet das, dass niemand daraus liest.

Das könnte falsch sein, aber einfache Tests zeigen, dass es funktioniert. Der FIFO-Pfad ist im obigen Programm fest codiert.

verwandte Informationen