操作系统第3次实验报告:管道
零、个人信息
- 姓名:陈韵
- 学号:201821121053
- 班级:计算1812
一、编写程序
在服务器上用Vim编写程序:创建一个命名管道,创建两个进程分别对管道进行读 fifo_read.c 与写 fifo_write.c。给出源代码如下
fifo_read.c:
1 #include <stdio.h>
2 #include <sys/stat.h>
3 #include <stdlib.h> // exit
4 #include <fcntl.h> //权限
5 #include <errno.h>
6 int main()
7 {
8 int fd;
9 int count = 0; //用于存储读取到的数据个数
10 int len; //从fifo中读取的数据长度
11 char buf[1024]; //数据流
12 //创建fifo管道
13 //创建fifo 授予可读可写的权限,同时确认是fifo创建失败而非文件已经存在。
14 if (mkfifo("fifo", 0666) < 0 && errno != EEXIST)
15 {
16 perror("创建fifo失败!");
17 }
18 //创建成功 以只读方式打开fifo
19 if ((fd = open("fifo", O_RDONLY)) < 0)
20 {
21 perror("打开fifo失败!");
22 exit(1);
23 }
24 //读取fifo管道
25 while ((len = read(fd, buf, 1024)) > 0)
26 {
27 count++;
28 printf("读取到的信息%d为:%s\n", count, buf);
29 }
30 printf("写入端关闭!");
31 close(fd);
32 return 0;
33 }
fifo_write.c:
1 #include <stdio.h>
2 #include <sys/stat.h>
3 #include <stdlib.h> // exit
4 #include <fcntl.h> //权限
5
6 int main()
7 {
8 int fd; //存放open的返回值
9 char buf[1024]; //存放数据流
10
11 printf("我是进程:%d,现在开始写入数据。\n若想停止输入请按~。 \n", getpid());
12 //以只写打开fifo
13 if ((fd = open("fifo", O_WRONLY)) < 0)
14 {
15 perror("打开fifo失败!");
16 exit(1);
17 }
18 //打开fifo成功 开始写入数据
19 while (1)
20 {
21 scanf("%s", buf);
22 //用于判断是否停止读入
23 if (strcmp(buf, "~") == 0)
24 break;
25 //根据输入的值 写入fifo中
26 if (write(fd, buf, strlen(buf) + 1) < 0)
27 {
28 perror("写入fifo失败!");
29 close(fd); //关闭打开的fifo
30 exit(1);
31 }
32 printf("写入FIFO:%s\n", buf);
33 }
34 close(fd);
35 return (0);
36 }
二、分析运行结果
1、先确保打开2个命令行窗口,一个用于读入,一个用于写入。并分别编译 fifo_read.c 与 fifo_write.c
2、先运行读端:fifo_read.c。此时用ls命令会发现fifo_read.c运行时所创建的FIFO文件
后运行写端:fifo_write.c。开始键入数据,最后以 " ~ " 停止输入。
3、过程分析:
-
- 当运行fifo_read.c与fifo_write.c后,因为写端还没有写入数据,此时的读端会处于阻塞状态,以等待写端的数据写入。于此同时写端也在等待用户键入数据。
- 当用户从写端键入数据后,写端的控制台会显示用户已经写入FIFO的数据,于此同时读端也会马上读取到用户刚刚写入的数据,并显示出来。
- 当用户键入“ ~ ” 后,写端停止写入,并关闭打开的FIFO,进程结束。与此同时读端因为没有读取到数据,打印出写入端关闭,进程结束
4、小结:
- 使用FIFO进行通信,每次传输的数据一定要在大小之内。
- 对FIFO的访问实际上可以转化成对文件的访问,诸如open/write/read等都是行得通滴。
- open以及mkfifo的第二个参数为文件的权限,常见的有:
- O_RDONLY 以只读的方式打开
- O_WRONLY 以只写的方式打开
- O_RDWR 以可读写的方式打开
- 同时注意open一个FIFO,根据是否设置非阻塞标志,有不同的情况:
- 默认为没有指定非阻塞标志,如本次实验。
- 只读open要阻塞到某个进程为写,才打开FIFO。
- 只写open同样要阻塞到某个进程为读,才打开它。
- 只读open要阻塞到某个进程为写,才打开FIFO。
- 若指定了非阻塞标志
- 只读open立即返回。
- 只写open将出错,并返回-1。
- 默认为没有指定非阻塞标志,如本次实验。
- 使用到FIFO的情况:
- 如本次实验,一个进程读数据,一个进程写数据。
- 实现client/server架构,客户端和服务端进行通信。
三. 通过该实验产生新的疑问及解答
1.管道pipe和命名管道FIFO,他们之间的差异是什么?是什么导致了这个差异???
FIFO可以用于任意2个进程的通信,而pipe只能用于父子进程、兄弟进程等具有血缘关系的进程之间的通信。
我们可以通过ls命令查看FIFO在文件系统中对应的inode,就是因为有了名字,所以它可用于任意两个进程之间的通信。而pipe没有名 字,在现有的文件系统中,都无法查找到它的存在。
2.如果FIFO可以实现C/S架构,那么可不可以实现多个客户端向同一个服务端发送信息?
可见目前的FIFO有多个写进程。问题来了,服务器端如何把回答送至各个对应的客户端呢?很显然此时不能再利用单个FIFO了。通过查 阅相关资料发现了一种可行的解决办法:每个客户进程都在请求中包含他自己的进程ID,然后服务器进程为每个客户进程独立创建一个 FIFO。