Verifique se o pipe nomeado está aberto para leitura

Verifique se o pipe nomeado está aberto para leitura

No momento, tenho uma verificação ruim para ver se um pipe nomeado está sendo lido:

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
}

se o kill funcionar (sai com 0), significa que ninguém estava lendo o pipe.

Mas em vez de ter um atraso de 0,25 segundo e iniciar um processo desnecessário, estou procurando uma maneira de verificar o pipe nomeado para ver se ele está aberto para leitura. Existe alguma maneira de determinar se algo está sendo lido?

Observação: Não consigo ler o pipe nesta chamada, só posso escrever nele (porque com pipes nomeados a ordem em que os leitores são anexados não parece ser respeitada - ou talvez seja o leitor mais recente que obtém os dados, não o leitor mais velho).

Responder1

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"; }

O /bin/echoserá eliminado por a SIGPIPEe retornará um status diferente de zero se não houver leitores.

Você não pode usar o built-in echo(mesmo em um subshell) porque ele SIGPIPEserá capturado ou matará todo o shell.

Assim como a versão do OP, isso é destrutivo. Se você possui GNU dd, você pode tentar abrir o arquivo com O_NONBLOCK, a partir de C:

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

Mas isso não é muito melhor; se houver outros escritores no pipe, o fechamento automático do fifo na saída do comando fará com que todos os leitores obtenham um EOF.

Observação:usar pipes nomeados é mais uma questão de masoquismo ou pedantismo padrão [1]. A API de soquetes BSD implementada pelos soquetes de domínio unix é incomparavelmente melhor (é por isso que governa o mundo ;-)), e existem programas como as versões mais recentes netcatque o tornam utilizável a partir do shell também.

[1] que é derrotado em exemplos como o acima ouessepelo fato de que abrir um fifo no modo rw é "indefinido" de acordo com o padrão, embora tenha sido implementado da mesma forma na maioria dos sistemas há cerca de 30 anos)).

Responder2

Eu roubei esse programa C dehttps://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);

}

se sair com 0, isso significa que alguém já está lendo o pipe nomeado? E se sair com 1, significa que ninguém está lendo isso.

Isso pode estar errado, mas os testes básicos dizem que funciona. O caminho fifo está codificado no programa acima.

informação relacionada