您在非阻塞模式下打开FIFO,这意味着 I/O 函数可能会因(-1 和 errno 设置为)EAGAIN 或 EWOULDBLOCK 而失败,而不是阻塞(等待)函数完成。在 Linux 中,FIFO 的开放描述符与pipes 具有相同的语义。
如果您费心检查错误(每当 open() 或 write() 返回 -1 指示错误时打印 strerror(errno)),您已经知道失败的原因。照原样,显示的代码甚至没有重现问题。以下代码,
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
const char *msg = "The Example Message.\n";
const size_t msg_len = strlen(msg);
int rfd, wfd;
if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *mypath = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", mypath);
fprintf(stderr, " %s FIFO\n", mypath);
fprintf(stderr, "\n");
fprintf(stderr, "This program tests opening and writing a short message to the FIFO.\n");
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
rfd = open(argv[1], O_RDONLY | O_NONBLOCK);
if (rfd == -1) {
fprintf(stderr, "%s: Cannot open FIFO for reading: %s.\n", argv[1], strerror(errno));
return EXIT_FAILURE;
}
wfd = open(argv[1], O_WRONLY | O_NONBLOCK);
if (wfd == -1) {
fprintf(stderr, "%s: Cannot open FIFO for writing: %s.\n", argv[1], strerror(errno));
return EXIT_FAILURE;
}
ssize_t n = write(wfd, msg, msg_len);
if (n == -1) {
fprintf(stderr, "%s: Cannot write to FIFO: %s.\n", argv[1], strerror(errno));
return EXIT_FAILURE;
} else
if (n != (ssize_t)msg_len) {
fprintf(stderr, "%s: Wrote only %zd of %zu bytes to the FIFO.\n", argv[1], n, msg_len);
return EXIT_FAILURE;
} else {
printf("Success!\n");
}
close(wfd);
close(rfd);
return EXIT_SUCCESS;
}
干净地编译 (gcc -Wall -Wextra -O2 source.c -o binary),并实现所示代码(但带有错误检查,并使用命令行参数作为要打开的 FIFO 的名称)。但是,它不会验证命名文件是否为 FIFO。如果在不存在的 FIFO 上运行,它会报错 “FIFO:无法打开 FIFO 进行读取:没有这样的文件或目录。”
如果你创建了 FIFO (mkfifo test-fifo) 并运行测试程序,没有错误;唯一的输出是“成功!”。
如果你创建了 FIFO,并且反复向它写入数据但从未从中读取数据,则在某些时候 FIFO 的内核缓冲区已满,运行测试程序将报告 "test-fifo: Cannot write到 FIFO:资源暂时不可用。”(这意味着 write() 返回 -1 且 errno==EWOULDBLOCK 或 errno==EAGAIN)。
你可以通过运行来模拟这个,例如bash -c 'exec 4<>test-fifo ; dd if=/dev/zero of=test-fifo bs=1 oflag=nonblock status=progress',它打开test-fifo FIFO 读写(在Linux 中总是成功)到描述符4,然后运行dd 用零填充它,使用Bash(子)shell。在我的系统上,一个 FIFO 可以容纳 65536 字节 (64k)。像这样填充 FIFO 后,运行测试程序 (./binary test-fifo) 将失败。
希望您能看到错误检查的重要性和实用性。这不是您应该考虑的“我稍后会在/如果我有时间的时候添加它们”;它们也是重要的开发工具。