檢查命名管道是否打開以供讀取

檢查命名管道是否打開以供讀取

現在,我有一個蹩腳的檢查來查看是否正在讀取命名管道:

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
}

如果終止有效(以 0 退出),則表示沒有人從管道中讀取資料。

但我不想有 0.25 秒的延遲並啟動不必要的進程,而是尋找一種方法來檢查命名管道以查看它是否已打開以供讀取?有沒有辦法確定是否有東西正在從中讀取?

筆記:我無法在這次調用中從管道中讀取數據,我只能寫入它(因為使用命名管道,讀取器的附加順序似乎不受尊重 - 或者可能是最近獲取數據的讀取器,不是最老的讀者)。

答案1

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

如果沒有讀者,則會/bin/echo被 a 殺死SIGPIPE並返回非零狀態。

您不能使用內建函數echo(即使在子 shell 中),因為它將SIGPIPE被捕獲或殺死整個 shell。

就像OP的版本一樣,這是破壞性的。如果您有 GNU dd,您可以嘗試使用 開啟文件O_NONBLOCK,如下所示C

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

但這也好不了多少;如果管道中有其他寫入者,則在命令退出時自動關閉 fifo 將導致所有讀取者獲得 EOF。

筆記:使用命名管道更多的是一種受虐狂或標準的迂腐行為[1]。由 unix 域套接字實現的 BSD 套接字 API 是無與倫比的好(這就是它統治世界的原因;-)),並且有一些程式(例如較新版本的程式)netcat使其也可以從shell 中使用。

[1] 在上面的例子中被擊敗或事實上,根據標準,在 rw 模式下開啟 fifo 是“未定義的”,儘管自 30 年前左右以來在大多數系統中都實現了相同的做法))。

答案2

我從這裡偷了這個C程序https://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);

}

如果它以 0 退出,這意味著有人已經在從命名管道讀取資料了?如果它以 1 退出,則表示沒有人正在讀取它。

這可能是錯誤的,但基本測試表明它是有效的。 fifo 路徑在上面的程式中是硬編碼的。

相關內容