目录
1.有名管道
1.1概述
1.2与无名管道的差异
2.有名管道的创建
2.1 直接用shell命令创建有名管道
2.2使用mkfifo函数创建有名管道
3.有名管道读写操作
3.1单次读写
3.2多次读写
4.有名管道进程间通信
4.1回合制通信
4.2父子进程通信
5.有名管道读写规律(默认阻塞)
5.1读写端都存在,只读不写
5.2读写端都存在,只写不读
5.3 在一个进程中,只有读端,没有写端
5.4 在一个进程中,只有写端,没有读端
5.5 一个进程只读,一个进程只写
5.5.1两个进程,一个只读一个只写
5.5.2两个进程,一个只读一个只写,关闭写端
5.5.3两个进程,一个只读一个只写,关闭读端
5.6读写端都存在,默认阻塞
6.有名管道的读写规律(设置:非阻塞)
6.1只读方式打开(设置非阻塞)
6.2只写方式打开(设置非阻塞)
6.3读写方式打开(设置非阻塞)
1.有名管道
1.1概述
1.2与无名管道的差异
特性 | 有名管道 | 无名管道 |
---|---|---|
进程关系 | 允许无亲缘关系的进程通信 | 仅限有亲缘关系的进程 |
存在形式 | 文件系统中的 FIFO 文件 | 内存中的临时缓冲区 |
持久性 | 文件删除前一直存在 | 进程终止后自动销毁 |
创建方式 | mkfifo() /mkfifoat() | pipe() |
2.有名管道的创建
2.1 直接用shell命令创建有名管道
在终端直接用shell命令mkfifo创建有名管道
使用ls -l命令查看 myfifo1文件的类型为p,表示该文件是一个管道文件。
2.2使用mkfifo函数创建有名管道
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:创建一个有名管道,产生一个本地文件系统可见的文件pathname
参数:
pathname:有名管道创建后生成的文件,可以带路径
mode:管道文件的权限,一般通过八进制数设置即可,例如0664
返回值:
成功:0
失败:‐1
(1)管道文件不存在
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
//通过mkfifo函数创建有名管道
if(mkfifo("fifo_file", 0664) == -1)
{
perror("fail to mkfifo");
exit(1);
}
return 0;
}
运行结果:管道文件不存在,创建了fifo_file管道文件
(2)管道文件存在
再次运行程序,报错:文件已存在
程序修改:如果错误码不是 EEXIST,继续运行
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
//通过mkfifo函数创建有名管道
if(mkfifo("fifo_file", 0664) == -1)
{
printf("errno = %d\n", errno);
//如果管道文件已经存在,不需要报错退出,直接使用即可,
//所以需要在错误输出之前把因为文件存在的错误排除
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
return 0;
}
运行结果:
终端输入: sudo find /usr/include -name "errno-base.h" ,查找错误码文件
3.有名管道读写操作
由于有名管道在本地创建了一个管道文件,所以系统调用的IO函数基本都可以对有名管道
进行操作, 但是不能使用lseek修改管道文件的偏移量.
注意:有名管道创建的本地的文件只是起到标识作用,真正有名管道实现进程间通信还是在
内核空间开辟内存,所以本地产生的文件只是一个标识,没有其他作用,对本地管道文件的
操作实质就是对内核空间的操作。
3.1单次读写
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define FIFONAME "fifo_file" //管道文件
int main(int argc, char const *argv[])
{
//通过mkfifo函数创建有名管道
if(mkfifo(FIFONAME, 0664) == -1)
{
if(errno != EEXIST)//如果不存在报错
{
perror("fail to mkfifo");
exit(1);
}
}
//对有名管道进行读写操作
//通过open函数打开管道文件并得到文件描述符
int fd;
fd = open(FIFONAME, O_RDWR);//权限:可读可写
if(fd == -1)
{
perror("fail to open");
exit(1);
}
//通过write函数向管道中写入数据
if(write(fd, "hello world", strlen("hello world")) == -1)
{
perror("fail to write");
exit(1);
}
//通过read函数读取管道中的数据
char buf[32] = "";
if(read(fd, buf, sizeof(buf)) == -1)
{
perror("fail to read");
exit(1);
}
printf("buf = [%s]\n", buf);
//使用close函数关闭文件描述符
close(fd);
return 0;
}
运行结果:
3.2多次读写
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define FIFONAME "fifo_file"
int main(int argc, char const *argv[])
{
//通过mkfifo函数创建有名管道
if(mkfifo(FIFONAME, 0664) == -1)
{
if(errno != EEXIST)//如果不存在报错
{
perror("fail to mkfifo");
exit(1);
}
}
//对有名管道进行操作
//管道后写入的数据会保存在之前写入数据的后面,不会替换
//如果管道中没有数据了,读操作会阻塞
//通过open函数打开管道文件并得到文件描述符
int fd;
fd = open(FIFONAME, O_RDWR);
if(fd == -1)
{
perror("fail to open");
exit(1);
}
//第一次 通过write函数向管道中写入数据
if(write(fd, "hello world", strlen("hello world")) == -1)
{
perror("fail to write");
exit(1);
}
//第2次 通过write函数向管道中写入数据
if(write(fd, "nihao", strlen("nihao")) == -1)
{
perror("fail to write");
exit(1);
}
//第1次 通过read函数读取管道中的数据,已将管道中的所有数据读取
char buf[32] = "";
if(read(fd, buf, sizeof(buf)) == -1)
{
perror("fail to read");
exit(1);
}
printf("第1次读取 buf = [%s]\n", buf);
//第2次 通过read函数读取管道中的数据,管道中已无数据
if(read(fd, buf, sizeof(buf)) == -1)
{
perror("fail to read");
exit(1);
}
printf("第2次读取 buf = [%s]\n", buf);
//使用close函数关闭文件描述符
close(fd);
return 0;
}
运行结果:第1次 通过read函数读取管道中的数据,已将管道中的所有数据读取;第2次 通过read函数读取管道中的数据,管道中已无数据,read函数执行阻塞;
4.有名管道进程间通信
4.1回合制通信
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
//如果没有创建有名管道,则创建有名管道
//为了实现两个进程都可以收发数据,所以需要创建两个有名管道
if(mkfifo("myfifo1", 0664) == -1)
{
if(errno != EEXIST)//如果不存在报错
{
perror("fail to mkfifo");
exit(1);//退出
}
}
if(mkfifo("myfifo2", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//打开两个有名管道并得到文件描述符
//fd_w:向管道myfifo1写入数据,fd_r:从管道myfifo2读取数据,
//另一个接收方正好相反
int fd_w, fd_r;
if((fd_w = open("myfifo1", O_WRONLY)) == -1)
{
perror("fail to open");
exit(1);
}
if((fd_r = open("myfifo2", O_RDONLY)) == -1)
{
perror("fail to open");
exit(1);
}
char buf[128] = "";
char buf1[128] = "";
ssize_t bytes;
while(1)
{
printf("发送端运行中:请输入向接收端要发送的内容\n");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf) - 1] = '\0';//将fgets最后输入的\n替换为\0,终端就没有空行
//send进程负责将数据写入myfifo1,接着从myfifo2中读取数据
//发送端将终端输入的数据写入myfifo1,接收端:myfifo2会读取写入的数据
if((bytes = write(fd_w, buf, sizeof(buf))) == -1)
{
perror("fail to write");
exit(1);
}
//发送端从myfifo2读取数据
if((bytes = read(fd_r, buf1, sizeof(buf1))) == -1)
{
perror("fail to read");
exit(1);
}
printf("发送端:读取到接收端发送的数据: %s\n", buf1);
memset(buf, 0, sizeof(buf));//buf清0
memset(buf1, 0, sizeof(buf1));
}
return 0;
}
接收端程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
if(mkfifo("myfifo1", 0664) == -1)
{
if(errno != EEXIST)//如果不存在报错
{
perror("fail to mkfifo");
exit(1);
}
}
if(mkfifo("myfifo2", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//fd_w:向管道myfifo2写入数据,fd_r:从管道myfifo1读取数据,
int fd_w, fd_r;
if((fd_r = open("myfifo1", O_RDONLY)) == -1)
{
perror("fail to open");
exit(1);
}
if((fd_w = open("myfifo2", O_WRONLY)) == -1)
{
perror("fail to open");
exit(1);
}
char buf[128] = "";
char buf1[128] = "";
ssize_t bytes;
while(1)
{
//recv进程负责从myfifo1中读取数据,接着将终端输入数据写入myfifo2
//接收端:读取myfifo1写入数据
if((bytes = read(fd_r, buf, sizeof(buf))) == -1)
{
perror("fail to read");
exit(1);
}
printf("接收端:读取到发送端发送的数据: %s\n", buf);
printf("接收端运行中,清输入要发送的内容: \n");
fgets(buf1, sizeof(buf1), stdin);
buf1[strlen(buf1) - 1] = '\0';
//接收端:向myfifo2写入数据,发送端:myfifo1会读取写入的数据
if((bytes = write(fd_w, buf1, sizeof(buf1))) == -1)
{
perror("fail to write");
exit(1);
}
memset(buf, 0, sizeof(buf));//buf清0
memset(buf1, 0, sizeof(buf1));
}
return 0;
}
运行结果:打开两个终端,分别运行发送端和接收端程序。发送和接收端程序运行时,发送端:先给接收端发送数据,保存在管道1;接着等待从管道2读取接收端发送的数据。接收端:从管道1读取发送端发送的数据;接着向发送端发送数据,保存在管道2。
程序缺点:只能一端输出后,等待另一端回复;回合制发送和接收。
优化:选择父子进程。一个用于发送,一个用于接收。
(1)发送端
(2)接收端
4.2父子进程通信
(1)发送端程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
//如果没有创建有名管道,则创建有名管道
//为了实现两个进程都可以收发数据,所以需要创建两个有名管道
if(mkfifo("myfifo1", 0664) == -1)
{
if(errno != EEXIST)//如果不存在报错
{
perror("fail to mkfifo");
exit(1);//退出
}
}
if(mkfifo("myfifo2", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//打开两个有名管道并得到文件描述符
//fd_w:向管道myfifo1写入数据,fd_r:从管道myfifo2读取数据,
//另一个接收方正好相反
int fd_w, fd_r;
if((fd_w = open("myfifo1", O_WRONLY)) == -1)
{
perror("fail to open");
exit(1);
}
if((fd_r = open("myfifo2", O_RDONLY)) == -1)
{
perror("fail to open");
exit(1);
}
char buf[128] = "";
char buf1[128] = "";
ssize_t bytes;
//使用fork函数创建子进程
pid_t pid;
if((pid = fork()) < 0)
{
perror("fail to fork");
exit(1);
}
else if(pid > 0) // 父进程
{
while(1)
{
printf("发送端运行中:请输入向接收端要发送的内容\n");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf) - 1] = '\0';//将fgets最后输入的\n替换为\0,终端就没有空行
//send进程负责将数据写入myfifo1,接着从myfifo2中读取数据
//发送端将终端输入的数据写入myfifo1,接收端:myfifo2会读取写入的数据
if((bytes = write(fd_w, buf, sizeof(buf))) == -1)
{
perror("fail to write");
exit(1);
}
memset(buf, 0, sizeof(buf));//buf清0
sleep(1);
}
}
else // 子进程
{
while(1)
{
//发送端从myfifo2读取数据
if((bytes = read(fd_r, buf1, sizeof(buf1))) == -1)
{
perror("fail to read");
exit(1);
}
printf("发送端:读取到接收端发送的数据: %s\n", buf1);
if(strcmp("end_end",buf1) == 0)
{
printf("发送端:读取到接收端发送的: 终止信号,退出\n");
exit(1);
}
memset(buf1, 0, sizeof(buf1));
sleep(1);
}
}
return 0;
}
(2)接收端程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
//如果没有创建有名管道,则创建有名管道
//为了实现两个进程都可以收发数据,所以需要创建两个有名管道
if(mkfifo("myfifo1", 0664) == -1)
{
if(errno != EEXIST)//如果不存在报错
{
perror("fail to mkfifo");
exit(1);//退出
}
}
if(mkfifo("myfifo2", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//打开两个有名管道并得到文件描述符
//fd_w:向管道myfifo1写入数据,fd_r:从管道myfifo2读取数据,
//另一个接收方正好相反
int fd_w, fd_r;
if((fd_w = open("myfifo1", O_WRONLY)) == -1)
{
perror("fail to open");
exit(1);
}
if((fd_r = open("myfifo2", O_RDONLY)) == -1)
{
perror("fail to open");
exit(1);
}
char buf[128] = "";
char buf1[128] = "";
ssize_t bytes;
//使用fork函数创建子进程
pid_t pid;
if((pid = fork()) < 0)
{
perror("fail to fork");
exit(1);
}
else if(pid > 0) // 父进程
{
while(1)
{
printf("发送端运行中:请输入向接收端要发送的内容\n");
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf) - 1] = '\0';//将fgets最后输入的\n替换为\0,终端就没有空行
//send进程负责将数据写入myfifo1,接着从myfifo2中读取数据
//发送端将终端输入的数据写入myfifo1,接收端:myfifo2会读取写入的数据
if((bytes = write(fd_w, buf, sizeof(buf))) == -1)
{
perror("fail to write");
exit(1);
}
memset(buf, 0, sizeof(buf));//buf清0
sleep(1);
}
}
else // 子进程
{
while(1)
{
//发送端从myfifo2读取数据
if((bytes = read(fd_r, buf1, sizeof(buf1))) == -1)
{
perror("fail to read");
exit(1);
}
printf("发送端:读取到接收端发送的数据: %s\n", buf1);
if(strcmp("end_end",buf1) == 0)
{
printf("发送端:读取到接收端发送的: 终止信号,退出\n");
exit(1);
}
memset(buf1, 0, sizeof(buf1));
sleep(1);
}
}
return 0;
}
运行结果:打开两个终端,分别运行发送端和接收端程序。发送和接收端程序运行时,发送端既可以接收多次数据,也可以发送多次数据;接收端也支持同时发送和接收多次数据。发送特殊字符end_end退出运行。
(1)发送端
(2)接收端
5.有名管道读写规律(默认阻塞)
5.1读写端都存在,只读不写
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
if(mkfifo("myfifo", 0664) == -1)
{
//如果管道文件已经存在,不需要报错退出,直接使用即可,
//所以需要在错误输出之前把因为文件存在的错误排除
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//读写端都存在,只读不写
//如果原本管道中有数据,则正常读取
//如果管道中没有数据,则read函数会阻塞等待
int fd;
if((fd = open("myfifo", O_RDWR)) == -1)
{
perror("fail to open");
exit(1);
}
//先写入数据验证,管道中有数据,则正常读取
write(fd, "hello world", 11);
char buf[128] = "";
read(fd, buf, sizeof(buf));
printf("buf = %s\n", buf);
//管道中已无数据,读取会阻塞。
read(fd, buf, sizeof(buf));
printf("buf = %s\n", buf);
return 0;
}
运行结果:读写端都存在,只读不写。
第一次读取,管道中有数据,正常读取;第二次读取,管道中已经无数据,在read处阻塞。
5.2读写端都存在,只写不读
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
//如果管道文件已经存在,不需要报错退出,直接使用即可,
//所以需要在错误输出之前把因为文件存在的错误排除
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//读写端都存在,只写不读
//当有名管道的缓冲区写满后,write函数会发生阻塞
//默认有名管道的缓冲区为64K字节
int fd;
if((fd = open("myfifo", O_RDWR)) == -1)
{
perror("fail to open");
exit(1);
}
int num = 0;
while(1)
{
write(fd, "", 1024);
num++;
printf("num = %d\n", num);
}
return 0;
}
运行结果:读写端都存在,只写不读 ;当有名管道的缓冲区写满后,write函数会发生阻塞;默认有名管道的缓冲区为64K字节。
5.3 在一个进程中,只有读端,没有写端
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//在一个进程中,只有读端,没有写端
//会在open函数的位置阻塞
printf("***********************\n");
int fd;
if((fd = open("myfifo", O_RDONLY)) == -1)
{
perror("fail to open");
exit(1);
}
printf("------------------------\n");
char buf[128] = "";
ssize_t bytes;
if((bytes = read(fd, buf, sizeof(buf))) == -1)
{
perror("fail to read");
exit(1);
}
printf("bytes = %ld\n", bytes);
printf("buf = %s\n", buf);
return 0;
}
运行结果:在一个进程中,只有读端,没有写端;会在open函数的位置阻塞(printf("------------------------\n"); 未执行)。
5.4 在一个进程中,只有写端,没有读端
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
//如果管道文件已经存在,不需要报错退出,直接使用即可,
//所以需要在错误输出之前把因为文件存在的错误排除
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//在一个进程中,只有写端,没有读端
//会在open函数的位置阻塞
printf("*****************************\n");
int fd;
if((fd = open("myfifo", O_WRONLY)) == -1)
{
perror("fail to open");
exit(1);
}
printf("-----------------------------\n");
write(fd, "hello world", 11);
printf("666\n");
sleep(1);
return 0;
}
运行结果:在一个进程中,只有写端,没有读端;会在open函数的位置阻塞
5.5 一个进程只读,一个进程只写
5.5.1两个进程,一个只读一个只写
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//在一个进程中,只有读端,没有写端
//会在open函数的位置阻塞
printf("***********************\n");
int fd;
if((fd = open("myfifo", O_RDONLY)) == -1)
{
perror("fail to open");
exit(1);
}
printf("------------------------\n");
char buf[128] = "";
ssize_t bytes;
if((bytes = read(fd, buf, sizeof(buf))) == -1)
{
perror("fail to read");
exit(1);
}
printf("bytes = %ld\n", bytes);
printf("buf = %s\n", buf);
return 0;
}
(2)只写程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
//如果管道文件已经存在,不需要报错退出,直接使用即可,
//所以需要在错误输出之前把因为文件存在的错误排除
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//在一个进程中,只有写端,没有读端
//会在open函数的位置阻塞
printf("*****************************\n");
int fd;
if((fd = open("myfifo", O_WRONLY)) == -1)
{
perror("fail to open");
exit(1);
}
printf("-----------------------------\n");
write(fd, "hello world", 11);
printf("666\n");
sleep(1);
return 0;
}
运行结果:打开2个终端,对同一个管道进行读写操作,读写端同时存在,程序没有阻塞在open。
(1)只写端,程序没有阻塞在open,(printf("------------------------\n"); 已执行)
(2)只读端,程序没有阻塞在open,(printf("------------------------\n"); 已执行)
5.5.2两个进程,一个只读一个只写,关闭写端
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//在一个进程中,只有写端,没有读端
//会在open函数的位置阻塞
printf("*****************************\n");
int fd;
if((fd = open("myfifo", O_WRONLY)) == -1)
{
perror("fail to open");
exit(1);
}
printf("-----------------------------\n");
while(1)
{
write(fd, "hello world", 11);
printf("666\n");
sleep(1);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//在一个进程中,只有读端,没有写端
//会在open函数的位置阻塞
printf("***********************\n");
int fd;
if((fd = open("myfifo", O_RDONLY)) == -1)
{
perror("fail to open");
exit(1);
}
printf("------------------------\n");
char buf[128] = "";
ssize_t bytes;
while(1)
{
if((bytes = read(fd, buf, sizeof(buf))) == -1)
{
perror("fail to read");
exit(1);
}
printf("bytes = %ld\n", bytes);
printf("buf = %s\n", buf);
sleep(1);
}
return 0;
}
运行结果:打开两个终端运行。一个进程只读,一个进程只写,都运行后,如果关闭写端,读端read会返回0。
(1)写端,运行几次后,关闭写端,终止运行。
(2)读端,关闭写端,读端read会返回0。
5.5.3两个进程,一个只读一个只写,关闭读端


5.6读写端都存在,默认阻塞
有名管道默认读写状态为阻塞,读写端同时存在,不会再open函数处阻塞。
程序:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int fd;
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//如果open设置为可读可写,默认:阻塞效果
char send[100] = "nihao world";
fd = open("myfifo", O_RDWR);//读写打开
if(fd < 0)
{
perror("fail open fifo");
exit(1);
}
write(fd, send, strlen(send));
char recv[100] = "";
read(fd, recv, sizeof(recv));
printf("read from my_fifo buf=[%s]\n",recv);
return 0;
}

6.有名管道的读写规律(设置:非阻塞)
6.1只读方式打开(设置非阻塞)
程序:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int fd;
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//如果open标志位设置为非阻塞,并且以只读的方式打开管道文件
//open函数和read函数都不会阻塞
fd = open("myfifo", O_RDONLY | O_NONBLOCK);
if(fd < 0)
{
perror("fail open fifo");
exit(1);
}
while(1)
{
char recv[100] = "";
bzero(recv, sizeof(recv));
read(fd, recv, sizeof(recv));
printf("read from my_fifo buf=[%s]\n",recv);
sleep(1);
}
return 0;
}
运行结果:管道只读 非阻塞打开,在 open函数 不阻塞,程序继续运行。
6.2只写方式打开(设置非阻塞)
程序:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int fd;
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//如果open标志位设置为非阻塞,并且以只写的方式打开管道文件
//open函数会直接报错
//如果open设置为可读可写,那么跟阻塞是一样的效果
char send[100] = "Hello world";
fd = open("myfifo", O_WRONLY | O_NONBLOCK);
//fd = open("myfifo", O_RDWR | O_NONBLOCK);
if(fd < 0)
{
perror("fail open fifo");
exit(1);
}
write(fd, send, strlen(send));
char recv[100] = "";
read(fd, recv, sizeof(recv));
printf("read from my_fifo buf=[%s]\n",recv);
return 0;
}
运行结果:管道只写 非阻塞打开管道文件,open函数会直接报错。(不加非阻塞设置,在open函数处,阻塞。见5.4章节)
6.3读写方式打开(设置非阻塞)
程序:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int fd;
if(mkfifo("myfifo", 0664) == -1)
{
if(errno != EEXIST)
{
perror("fail to mkfifo");
exit(1);
}
}
//如果open设置为可读可写,那么跟阻塞是一样的效果
char send[100] = "Hello world";
//fd = open("myfifo", O_WRONLY | O_NONBLOCK);
fd = open("myfifo", O_RDWR | O_NONBLOCK);//读写打开
if(fd < 0)
{
perror("fail open fifo");
exit(1);
}
write(fd, send, strlen(send));
char recv[100] = "";
read(fd, recv, sizeof(recv));
printf("read from my_fifo buf=[%s]\n",recv);
return 0;
}
运行结果:读写端同时存在,设置为非阻塞,不会再open函数处阻塞。效果与读写端同时存在,设置为阻塞,效果相同。