操作系统第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
",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("自命名管道文件打开失败!!!
");
          exit(-1);
      }
      //fifo文件打开成功
      printf("请输入要写入管道的内容(输入##结束)
");
     while(1){
          memset(buff, 0, sizeof(buff));
          fgets(buff,MAX,stdin);//获取用户输入一行的值
          if(strcmp(buff,"##
")==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("自命名管道文件打开失败!!!
");
         exit(-1);
     }
     //fifo文件打开成功
     printf("从管道中读取的内容为
");
     while(read(fr,buff,MAX)!=0){//写入端还未关闭
         count++;
         printf("第%d次读取的内容:%s",count,buff);//取出写入端写入fifo中的内容
         memset(buff, 0, sizeof(buff));
     }
     printf("写文件端已经关闭!!!
");
     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

原文地址:https://www.cnblogs.com/lty1661489001/p/12708601.html