操作系统第3次实验报告:管道
- 袁祎琦
- 201821121033
- 计算1812
1. 编写程序
创建命名管道是用FIFO.c文件实现,对管道进行写是FIFOwrite.c来实现的,对管道进行读是FIFOread.c来实现的。
1、如果创建成功,那么mkfifo()返回0,如果失败,那么返回-1。
2、后面的操作,把这个命名管道当作文件进行操作,包括:open(),write(),read(),close()。
3、打开命名管道 int fd = open(char name,int how);
name表示文件名字字符串,how指的是打开的模式:
O_RDONLY(只读),
O_WRONLY(只写),
O_RDWR (可读可写),成功的话返回一个正整数,失败的话返回-1
注意:使用open()打开命名管道时可能会导致阻塞,如果同时用读写方式(O_RDWR)打开,则一定不会导致阻塞。
用法:对于下面三个文件,首先编译并运行FIFO.c文件(功能是创建命名通道),然后编译FIFOwrite.c和FIFOread.c文件,运行这两个文件生成的可执行程序,然后在write端发送信息,看read端是否可以接收到。
1 //FIFO.c文件 2 //此文件的功能是创建管道,这样在后续的读写代码中就不用判断管道是否存在。 3 #include <stdio.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/stat.h> 7 8 //创建命名管道 9 int main(){ 10 int ret = mkfifo("fifo2",0777); 11 if(ret == -1){ 12 perror("mkfifo"); 13 return -1; 14 } 15 return 0; 16 }
1 //FIFOwrite.c文件 2 #include <stdio.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <string.h> 7 #include <fcntl.h> 8 #define SIZE 1024 9 //从终端输入,并将输入写入管道 10 int main(){ 11 int fd = open("fifo2", O_WRONLY);//以只写的方式打开命名管道文件 12 if (fd== -1){ 13 perror ("mkfifo"); 14 return -1; 15 } 16 char buf[SIZE]; 17 while (1){ 18 fgets (buf, SIZE, stdin); 19 write (fd, buf, strlen(buf));//写数据 20 } 21 return 0; 22 }
1 //FIFOread.c文件 2 #include <stdio.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <string.h> 7 #include <fcntl.h> 8 #define SIZE 1024 9 10 //从管道内读数据 11 int main(){ 12 int fd = open("fifo2", O_RDONLY);//以只读的方式打开命名管道 13 if (fd == -1){ 14 perror ("mkfifo"); 15 return -1; 16 } 17 char buf[SIZE]; 18 while (1){ 19 int ret = read (fd, buf, SIZE);//读数据 20 buf[ret] = '\0'; 21 printf ("读到 %d 字节: %s\n", ret, buf); 22 } 23 return 0; 24 }
2. 分析运行结果
这个管道的读和写类似于聊天,一段“发送”,一端“接收”,在“写端”中输入需要传输到“读端”的内容,通过创建的管道,我创建的管道名为fifo2,然后“读端”接受“写端”输入的数据,另外还对输入的字符长度进行了统计。
只有在“写端”写入内容并,“读端”才会接收到内容。
3. 通过该实验产生新的疑问及解答
1、open()调用的阻塞是怎么回事?
答:对于只读方式,如果是open(char name,O_RDONLY),除非有一个进程以写的方式打开同一个命名管道,否则不返回;如果是open(char name,O_RDONLY | O_NONBLOCK),则即使没有其他进程以写的方式打开同一个命名管道,open()的调用也会成功并立即返回。
类似的,对于只写方式,如果open(char name,O_WRONLY),除非有一个进程以只读方式打开同一命名管道,否则open()调用将被阻塞;如果是open(char name,O_WRONLY|O_NONBLOCK),open()会立即返回,但要是没有其他进程以只读方式打开同一命名管道,open()将返回-1。
2、三个及三个以上的进程在命名管道进行通信,会不会信息混乱?
答:前面的例子是两个进程之间的通信问题,如果要是有多个进程同时向同一个FIFO写数据,而只有一个读进程在同一个FIFO内读取数据。
比如一个人输入:你好小明,另一个人输入:妈妈,那么那个read端本来是小明操作,但是他接收到的是:你好小明妈妈。这样是不是会很尴尬,当然,这是我个人的设想,我一个人无法同时发送这两句话,所以这个验证没有成功。感觉理论上是会发生的,因为,如下,两个write都输入一句话,read都接收到了,如果两个write同时输入,是不是就……
3、想结束这个通信进程的话要怎么做?
答:由于对终端的操作还不是很熟练,上面的write端一直回车就是不结束,后面在网上搜索到ctrl+c可以结束进程。
4. 加分项
上述代码实现的是单程通信,即只有在“写端”写入内容时“读端”才接收消息,能否改造上述代码,使之实现双向通信?
思路是,一方先发起通信,将输入通道打开并且输入数据之后,立即关闭输入通道,然后打开接收通道,等待接收对方的信息;然后另一方打开接收通道接收对方发送的信息,接收成功后关闭接收通道,然后打开写入通道回复对方消息。所以,以下的程序只支持每次一条信息的发送,除非一行输入好几句话再回车。
1 #include <stdio.h> 2 #include <string.h> 3 #include <fcntl.h> 4 #include <sys/stat.h> 5 #include <sys/types.h> 6 #include <unistd.h> 7 int main(){ 8 int fd; 9 char * myfifo = "/home/yuanyiqi/fifo3";//FIFO路径 10 mkfifo(myfifo, 0666); 11 char read1[100], write1[100];//两个数组存储双方的字符 12 while (1){ 13 fd = open(myfifo, O_WRONLY);//只写打开FIFO 14 fgets(write1, 100, stdin);//write先发出信息 15 write(fd, write1, strlen(write1)+1);//写入缓冲 16 close(fd);//write关闭 17 fd = open(myfifo, O_RDONLY);//只读打开FIFO 18 read(fd, read1, sizeof(read1));//读取对方数据 19 printf("User2: %s\n", read1);//显示对方发送内容 20 close(fd); 21 } 22 return 0; 23 }
1 #include <stdio.h> 2 #include <string.h> 3 #include <fcntl.h> 4 #include <sys/stat.h> 5 #include <sys/types.h> 6 #include <unistd.h> 7 int main(){ 8 int fd1; 9 char * myfifo = "/home/yuanyiqi/fifo3";//FIFO路径 10 mkfifo(myfifo, 0666); 11 char read1[100], write1[100];//两个数组存储双方的字符 12 while (1){ //跟write相反 13 fd1 = open(myfifo,O_RDONLY);//只读打开FIFO 14 read(fd1, read1, 100);//读取对方发送的信息 15 printf("User1: %s\n", read1);//显示对方发送内容 16 close(fd1);//read关闭 17 fd1 = open(myfifo,O_WRONLY);//只写打开FIFO 18 fgets(write1, 100, stdin);//恢复对方 19 write(fd1, write1, strlen(write1)+1);//写数据 20 close(fd1); 21 } 22 return 0; 23 }
参考链接:
https://blog.csdn.net/daaikuaichuan/article/details/82827994