操作系统第3次实验报告:管道
0.个人信息
- 姓名 罗廷杨
- 学号 201821121013
- 班级 计算1811
1. 编写程序
在服务器上用Vim编写程序:创建一个命名管道,创建两个进程分别对管道进行读fifo_read.c
和写fifo_write.c
。源代码如下:
1.fifo_write.c
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<fcntl.h> #include<errno.h> #include<signal.h> #define MAX 128 #define FIFO "./fifo" //写端 void delSignal(int sig){ printf("读端已经关闭!!SIGPIPE的信号值为%d\n",sig); exit(-1); } int main(){ //读端直接关闭,写端写完数据就会发送这个信号终止进程 signal(SIGPIPE,delSignal); //建立自命名管道 if(mkfifo(FIFO, 0640) == -1) { if(errno != EEXIST)//如果错误类型是fifo类型文件已经存在那么继续执行 { perror("mkfifo"); exit(-1); } } char buff[MAX]; int fw=open(FIFO,O_WRONLY);//以只写的形式打开有名管道文件fifo if(fw==-1){//fifo文件打开失败 printf("自命名管道文件打开失败!!!\n"); exit(-1); } //fifo文件打开成功 printf("请输入要写入管道的内容(输入##结束)\n"); while(1){ memset(buff, 0, sizeof(buff)); fgets(buff,MAX,stdin);//获取用户输入一行的值 if(strcmp(buff,"##\n")==0){//判断是否结束写入 break; } write(fw,buff,strlen(buff));//将用户输入的值将写入fifo } close(fw); return 0; }
2.fifo_read.c
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<fcntl.h> #include<errno.h> #define MAX 128 #define FIFO "./fifo" //读端 int main(){ if(mkfifo(FIFO, 0640) == -1) { if(errno != EEXIST)//如果错误类型是fifo类型文件已经存在那么继续执行 { perror("mkfifo"); exit(-1); } } char buff[MAX]={0}; int count=0; int fr=open(FIFO,O_RDONLY);//以只读的形式打开有名管道文件fifo if(fr==-1){//fifo文件打开失败 printf("自命名管道文件打开失败!!!\n"); exit(-1); } //fifo文件打开成功 printf("从管道中读取的内容为\n"); while(read(fr,buff,MAX)!=0){//写入端还未关闭 count++; printf("第%d次读取的内容:%s",count,buff);//取出写入端写入fifo中的内容 memset(buff, 0, sizeof(buff)); } printf("写文件端已经关闭!!!\n"); close(fr); return 0; }
2. 分析运行结果
1.正常执行情况下的运行结果
./write的运行结果
./read的运行结果
当运行./write和./read但是还没有往管道里面写入数据时,./write和./read都会先处于阻塞状态,我们可以观察到两个程序都没有继续运行。当在./write程序中输入数据,这时./write程序就会往管道内写入数据,数据写入完成后就会被./read程序检测到,然后将数据读出显示到控制台中。当往./write中输入##那么写程序就结束执行,这样一来./read程序就无法在管道内读取到数据,因此也结束执行。
2../write强制退出的运行结果
./write的运行结果
./read的运行结果
./write程序强制退出,也就是说没有程序往管道中写入数据了,那么./read就无法从管道中读取数据因此也随之结束运行。
3../read强制退出的运行结果
./read的运行结果
./write的运行结果
当./read程序强制退出之后,./write程序再往管道中写入数据那么就会产生异常,继而产生信号--SIGPIPE(13)来结束运行。
说明
创建命名管道的方式有两种,一种是在程序中创建,另一种是直接在命令行中创建。
1.在程序中创建
使用函数 int mkfifo(const char *filename, mode_t mode);
其中mode(管道模式)有如下几种:
O_RDONLY:读管道。
O_WRONLY:写管道。
O_RDWR:读写管道。
O_NONBLOCK:非阻塞。
O_CREAT:如果该文件不存在,就创建一个新的文件,并使用第3个参数为其设置权限。
O_EXCL:测试文件是否存在。
2.使用命令行创建
mkfifo filename
3. 通过该实验产生新的疑问及解答
疑问:signal(SIGPIPE,delSignal);的处理过程是什么样子的?
解答:signal是一个带signum和handler两个参数的函数,需要处理的信号由参数signum给出,接收到指定信号时将要调用的函数由handler给出,此处signum对应于SIGPIPE,handler对应于delSignal。./write程序执行过程中,当./read进程结束信号没有发生时,./write进程正常运行,当信号发生时,./write进程的正常运行会被中断,然后去处理SIGPIPE信号,一看需要处理的信号是SIGPINE,就会从“信号处理方式登记表”中找到对应的信号处理函数,此处是delSignal函数,然后取出该函数的地址并执行该函数,从而打印出相应的提示信息并结束./write进程。
参考文献
【1】https://blog.csdn.net/qq_39755395/article/details/78568953
【2】https://www.cnblogs.com/zhanggaofeng/p/6075725.html