一、有名管道
1. 为何提出有名管道的说法,目的是为了克服无名管道的不足之处:
- 无名管道只能是用于具有亲缘关系的进程之间,这就限制了无名管道的使用范围。
- 有名管道可以使互不相关的两个进程互相通信,有名管道可以通过路径名来指出,并在文件系统课件
为了这种有名管道,Linux中专门设立了一个专门的特殊文件系统-管道文件,以FIFO的形式存在于文件系统中,这样,即使与FIFO的创建者不存在亲缘关系的进程,只要访问该路径,就能彼此通过FIFO相互通信,因此,通过FIFO不相关的进程也能交换数据,但在磁盘只是一个节点,而文件的数据只存在内存缓冲页面上,与普通管道一样。
2. 有名管道的创建
- 有名管道可以从命令行上创建,命令行方法是使用下面这个命令:
$ mkfifo myfifo
- 有名管道也可以从程序里创建,相关API有:
#include <sys/stat/h>
int mkfifo(cosnt char *path, mode_t mode);
参数:
- 第一个参数是一个普通的路径名,也就是创建后FIFO名字。
- 第二个参数与打开普通文件的open函数中的mode参数相同(文件的读写权限),如果mkfifo的一个参数是一个已经存在路径名时,会返回EEXIST错误,所以一般典型的调用代码会检查是否返回该错误,如果确实返回该错误,那么要调用打开FIFO的函数open就可以了。
3. FIFO的open函数打开规则:
O_RDONLY、O_WRONLY和O_NONBLOCK标志共有四种合法的组成方式:
- flags = O_RDONLY:open将会调用阻塞,除非有另外一个进程以写的方式打开用一个FIFO,否则一直等待。
- flags = O_WRONLY:open将会调用阻塞,除非有另外一个进程以读的方式打开同一个FIFO,否则一直等待。
- flags = O_RDONLY | O_NONBLOCK:如果此时没有其他进程以写的方式打开FIFO,此时open也会成功返回,此时FIOF被读打开,而不会返回错误。
- flag是= O_WRONLY | O_NONBLOCK:立即返回,如果此时没有其他进程以读的方式打开,open会失败打开,此时FIOF没有被打开,返回-1。
二、程序清单
1. 测试代码:
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>int main(int argc, const char *argv[])
{int ret = mkfifo("myfifo", 0666);if (ret == -1) {perror("mkfifo");exit(-1);}return 0;
}
输出结果:
2. 测试代码:
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>int main(int argc, const char *argv[])
{if (access(argv[1], F_OK) != 0) {int ret = mkfifo(argv[1], 0666);if (ret == -1) {perror("mkfifo");exit(-1);}}return 0;
}
输出结果:
3. 测试代码:
程序1:
// writefifo.c
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>int main(int argc, const char *argv[])
{int fd, nwrite;char buf[1024] = "\0";if (access(argv[1], F_OK) != 0) {int ret = mkfifo(argv[1], 0666);if (ret == -1) {perror("mkfifo");exit(-1);}}fd = open(argv[1], O_WRONLY);if (fd == -1) {perror("open");return -1;}while (1) {fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';nwrite = write(fd, buf, strlen(buf));if (nwrite == -1) {perror("write error");return -1;}if (!strncmp(buf, "quit", 4))break;}return 0;
}
2. 程序2:
//readfifo.c
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, const char *argv[])
{int ret, fd, nread;char buf[1024] = "\0";if (access(argv[1], F_OK) != 0) {ret = mkfifo(argv[1], 0666);if (ret == -1) {perror("mkfifo");exit(-1);}}fd = open(argv[1], O_RDONLY);if (fd == -1) {perror("open");exit(-1);}while (1) {nread = read(fd, buf, sizeof(buf));if (nread == -1) {perror("read errro");exit(-1);}printf("read from fifo is %s\n", buf);if (!strncmp(buf, "quit", 4))break;memset(buf, '\0', sizeof(buf));}return 0;
}
输出结果:
【题目】验证:flags = O_RDONLY | O_NONBLOCK:如果此时没有其他进程以写的方式打开FIFO,此时open也会成功返回,此时FIOF被读打开,而不会返回错误。
3. 测试代码:
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, const char *argv[])
{int ret, fd, nread;char buf[1024] = "\0";if (access(argv[1], F_OK) != 0) {ret = mkfifo(argv[1], 0666);if (ret == -1) {perror("mkfifo");exit(-1);}}fd = open(argv[1], O_RDONLY | O_NONBLOCK);if (fd == -1) {perror("open");exit(-1);}printf("open read fifo successfully\n");while (1) {nread = read(fd, buf, sizeof(buf));if (nread == -1) {perror("read errro");exit(-1);}printf("read from fifo is %s\n", buf);if (!strncmp(buf, "quit", 4))break;memset(buf, '\0', sizeof(buf));}return 0;
}
输出结果:
【题目】验证:flag是= O_WRONLY | O_NONBLOCK:立即返回,如果此时没有其他进程以读的方式打开,open会失败打开,此时FIOF没有被打开,返回-1。
4. 测试代码:
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>int main(int argc, const char *argv[])
{int fd, nwrite;char buf[1024] = "\0";if (access(argv[1], F_OK) != 0) {int ret = mkfifo(argv[1], 0666);if (ret == -1) {perror("mkfifo");exit(-1);}}fd = open(argv[1], O_WRONLY | O_NONBLOCK);if (fd == -1) {perror("open");return -1;}printf("open write fifo successfully\n");while (1) {fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';nwrite = write(fd, buf, strlen(buf));if (nwrite == -1) {perror("write error");return -1;}if (!strncmp(buf, "quit", 4))break;}return 0;
}
输出结果: