use*_*139 9 linux perl posix named-pipes
是否有一种方法(在C中,或最好在Perl中)来确定是否可以写入命名管道 - 即有一个活动的读取过程似乎如果我打开写入非阻塞,则open会立即返回但是select for write也立即返回.目标是如果读取结束没有准备好,写入过程只是继续(即跳过发送)
有可能你没有注意到的返回码open
.如果打开FIFO进行写入和非阻塞,则有两种可能的结果.
如果已有读者,open
则会立即成功返回.
如果没有管道读取器,open
则会因errno = ENXIO而失败.
以下程序演示.
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#include <sys/stat.h>
#define SERVFIFO "/tmp/server.fifo"
#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);
if (mkfifo(SERVFIFO, FILE_MODE) < 0 && errno != EEXIST)
syserr("mkfifo");
// try to open for write with no readers
int fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);
if (fdw == -1)
perror("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);
unlink(SERVFIFO);
}
Run Code Online (Sandbox Code Playgroud)
也就是说,open
没有阻塞失败的事实并不是那么有用.关于你唯一能做的就是不断尝试打开,直到你成功,这种轮询可能是浪费,而在长期运行程序的情况下,等待间歇性读者是有点荒谬的.
一种解决方案是上面使用的 - 打开FIFO以便自己阅读 - 但这有其自身的问题.
如果你在你的select
语句中使用你的FIFO写fd 它总是可写的......直到它没有.也就是说,因为您也是自己的读者,所以FIFO写入将成功,直到您使用PIPE_BUF字节填充FIFO缓冲区.之后,FIFO将无法写入,并且您的写入将在EAGAIN中失败,直到合法的读取器(即非您自己)出现,打开以进行读取,并开始耗尽缓冲区.
通过打开自己的FIFO进行读写,合法用户在关闭FIFO时不会看到EOF.由于您只关心写作,这对您来说可能不是问题.
我从未尝试过的另一种可能的解决方案是在FIFO上使用inotify.您可以监视您的inotify文件描述符,select
并确定何时有人打开了FIFO.然后你知道你可以安全地打开你的写作结束.您可能希望屏蔽FIFO上的开放权限,以便您可以成为唯一的编写者,如果可能的话,您的应用程序.
对于这些时髦的语义,FIFO应该被重命名为PITA.如果你可以做出改变,这就是为什么Unix神给了我们凡人的域名套接字.
无论任何其他设置如何,打开管道的写入侧都会阻塞,直到读取器打开读取侧。open
因此,在管道连接之前您无法返回。
如果读取器关闭已打开管道的一侧,则写入器将在下一次尝试写入时收到 E_PIPE。据我所知,这是管道不再连接的唯一指示。
归档时间: |
|
查看次数: |
5844 次 |
最近记录: |