操作系统第三次实验报告——有名管道(FIFO)
0 个人信息
- 张樱姿
- 201821121038
- 计算1812
1 实验目的
- 掌握进程间通信管道的编程。
2 实验内容
- 在服务器上用VIM编写一个程序:创建一个命名管道,创建两个进程分别对管道进行读(
read_fifo.c)
和写(write_fifo.c)
。给出源代码 - 给出运行结果,并分析
3 实验报告
3.1 编写写管道程序(write_fifo.c)
1 #include<unistd.h> //write,read,close,access 2 #include<string.h> //memset 3 #include<errno.h> //errno 4 #include<fcntl.h> //open,O_WRONLY,O_RDONLY 5 #include<stdio.h> //printf,sscanf 6 #include<stdlib.h> //exit 7 #include<limits.h> //PIPE_BUF 8 9 #define MYFIFO "/tmp/myfifo" //有名管道文件名 10 #define BUFES PIPE_BUF 11 12 int main(int argc,char * argv[]) 13 { 14 int fd,n; 15 char buff[BUFES]; 16 17 if(argc <= 1) 18 { 19 exit(1); 20 } 21 sscanf(argv[1],"%s",buff); 22 //以只写阻塞方式打开FIFO管道 23 fd = open(MYFIFO,O_WRONLY); 24 if(fd==-1) 25 { 26 printf("Open fifo error\n"); 27 exit(1); 28 } 29 //向管道中写入字符串 30 if((n = write(fd,buff,BUFES))>0) 31 { 32 printf("Finish writing '%s' to FIFO\n",buff); 33 } 34 close(fd); 35 exit(0); 36 }
3.2 编写读管道程序(read_fifo.c)
1 #include<unistd.h> //write,read,close,access 2 #include<string.h> //memset 3 #include<errno.h> //errno 4 #include<fcntl.h> //open,O_WRONLY,O_RDONLY 5 #include<stdio.h> //printf,sscanf 6 #include<stdlib.h> //exit 7 #include<limits.h> //PIPE_BUF 8 9 #define MYFIFO "/tmp/myfifo" 10 #define BUFES PIPE_BUF 11 12 int main() 13 { 14 int fd,n; 15 char buff[BUFES]; 16 //判断有名管道是否已存在 17 if(access(MYFIFO,F_OK)==-1) 18 { //若不存在,则创建可读可写的有名管道 19 if((mkfifo(MYFIFO,0666)<0)&&(errno != EEXIST)) 20 { 21 printf("Could't create fifo\n"); 22 exit(1); 23 } 24 } 25 //以只读阻塞方式打开有名管道 26 fd = open(MYFIFO,O_RDONLY); 27 if(fd==-1) 28 { 29 printf("Open fifo error\n"); 30 exit(1); 31 } 32 //不停读取管道中的数据,如果没用数据可读,则一直处于阻塞状态 33 while(1) 34 { 35 memset(buff,0,sizeof(buff)); 36 if((n = read(fd,buff,BUFES))>0) 37 { 38 printf("Read '%s' from FIFO\n",buff); 39 } 40 } 41 close(fd); 42 exit(0); 43 }
3.3 运行结果及分析
为了能够较好地观察运行结果,将两程序分别编译后,把这两个程序分别在两个终端里运行,在这里首先启动读管道程序。读管道进程在建立管道后就开始循环地从管道里读出内容,如果没有数据可读,则一直阻塞到写管道进程向管道写入数据。在启动了写管道程序后,读进程能够从管道里读出用户的输入内容,程序运行结果如下:
分析:
①对于读进程:
· 若该管道是阻塞打开,且当前FIFO内无数据,则对读进程而言一直阻塞到有数据写入。
· 若该管道是非阻塞打开,则不论FIFO内是否有数据,都进程都会立即执行读操作。也就是说若FIFO内无数据,那么读程序将立马返回0。
此处使用的是阻塞方式。
②对于写进程:
· 若该管道是阻塞打开,则写进程将一直阻塞到有数据写入。
· 若该管道是非阻塞打开而不能写入全部数据,则对读进程而言只能进行部分写入或者调用失败。
③管道模式:
· O_RDONLY:读管道。
· O_WRONLY:写管道。
· O_RDWR:读写管道。
· O_NONBLOCK:非阻塞。
· O_CREAT:如果该文件不存在,就创建一个新的文件,并使用第3个参数为其设置权限。
· O_EXCL:测试文件是否存在。如果使用O_CREAT|O_CREAT时文件存在,那么将返回出错:errno == EEXIST。
3.4 创建两个有名管道实现聊天程序
服务器端程序:
1 /*Server.c*/ 2 #include<unistd.h> 3 #include<string.h> 4 #include<errno.h> 5 #include<fcntl.h> 6 #include<stdio.h> 7 #include<stdlib.h> 8 #include<limits.h> 9 10 #define WRITE_FIFO "/tmp/readfifo" 11 #define READ_FIFO "/tmp/writefifo" 12 #define BUFES PIPE_BUF 13 14 int main(int argc,char * argv[]) 15 { 16 int wfd,rfd,n; 17 char buff[BUFES],readbuff[BUFES]; 18 //创建管道WRITE_FIFO 19 mkfifo(WRITE_FIFO, S_IFIFO|0666); 20 //以只读阻塞方式打开FIFO管道 21 rfd = open(READ_FIFO,O_RDONLY); 22 //以只写阻塞方式打开FIFO管道 23 wfd = open(WRITE_FIFO,O_WRONLY); 24 //不停读取管道中的数据,如果没用数据可读,则一直处于阻塞状态 25 while(1){ 26 memset(readbuff,0,sizeof(readbuff)); 27 if((n = read(rfd,readbuff,BUFES))>0) 28 { 29 readbuff[BUFES] = '\0'; 30 printf("Client: %s\n",readbuff); 31 } 32 memset(buff,0,sizeof(buff)); 33 printf("Server: "); 34 fgets(buff, BUFES, stdin); 35 buff[strlen(buff)-1] = '\0'; 36 37 write(wfd,buff,strlen(buff)); 38 } 39 close(wfd); 40 close(rfd); 41 exit(0); 42 }
客户端程序:
1 /*Client.c*/ 2 #include<unistd.h> 3 #include<string.h> 4 #include<errno.h> 5 #include<fcntl.h> 6 #include<stdio.h> 7 #include<stdlib.h> 8 #include<limits.h> 9 10 #define WRITE_FIFO "/tmp/writefifo" 11 #define READ_FIFO "/tmp/readfifo" 12 #define BUFES PIPE_BUF 13 14 int main(int argc,char * argv[]) 15 { 16 int wfd,rfd,n; 17 char buff[BUFES],readbuff[BUFES]; 18 //创建管道READ_FIFO 19 mkfifo(WRITE_FIFO, S_IFIFO|0666); 20 //以只写阻塞方式打开FIFO管道 21 wfd = open(WRITE_FIFO,O_WRONLY); 22 //以只读阻塞方式打开FIFO管道 23 rfd = open(READ_FIFO,O_RDONLY); 24 //不停读取管道中的数据,如果没用数据可读,则一直处于阻塞状态 25 while(1) 26 { 27 memset(buff,0,sizeof(buff)); 28 printf("Client: "); 29 fgets(buff, BUFES, stdin); 30 buff[strlen(buff)-1] = '\0'; 31 32 write(wfd,buff,strlen(buff)); 33 memset(readbuff,0,sizeof(readbuff)); 34 if((n = read(rfd,readbuff,BUFES))>0) 35 { 36 printf("Server: %s\n",readbuff); 37 } 38 } 39 close(wfd); 40 close(rfd); 41 exit(0); 42 }
3.5 运行效果及分析
分析:在这里首先启动客户端程序,再启动服务器端程序。客户端在建立管道后,首先写入数据到管道中,接着数据传递到服务器端,然后服务器端将数据写入管道中,再传递到客户端,如此往复循环。如果没有数据可读,则一直阻塞到写管道进程向管道写入数据。