0 個人信息 張櫻姿 201821121038 計算1812 1 實驗目的 掌握進程間通信管道的編程。 2 實驗內容 在伺服器上用VIM編寫一個程式:創建一個命名管道,創建兩個進程分別對管道進行讀(read_fifo.c)和寫(write_fifo.c)。給出源代碼 給出運行結果,並分析 3 實驗報 ...
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 運行效果及分析
分析:在這裡首先啟動客戶端程式,再啟動伺服器端程式。客戶端在建立管道後,首先寫入數據到管道中,接著數據傳遞到伺服器端,然後伺服器端將數據寫入管道中,再傳遞到客戶端,如此往複迴圈。如果沒有數據可讀,則一直阻塞到寫管道進程向管道寫入數據。
4 References
- https://blog.csdn.net/ccskyer/article/details/24989961
- https://blog.csdn.net/MONKEY_D_MENG/article/details/5570468
- https://blog.csdn.net/CSDN_LQR/article/details/52170717