C语言进程间通信 FIFO例子

本文深入探讨了进程间通信(IPC)的基本概念和技术,包括无名管道(PIPE)和有名管道(FIFO)的特点与应用场景。详细介绍了这两种管道的工作原理、创建方式、读写操作及其注意事项。

进程间通信:
1: 资源共享 --- 
2: 数据传输 --- 发送接受信息
3: 通知事件 --- 信号
4: 进程控制 --- 控制进程状态转换

比较古老:
无名管道(PIPE)
有名管道(FIFO ,named pipe)
信号(signal)

SYSTEM V IPC
信号量(Sem)
共享内存(shm)
消息队列(Msg)

BSD 
套接字(Socket)---- 网络编程

无名管道(PIPE)

int fd[2];
读0写1 -- 只能往read fd[0] , write [1];

open(无) --->  pipe 已有创建并打开功能
read / write / close 

无名管道只能用在有亲缘关系的进程中,进程结束了也随之消失( 局限)
一定是先pipe申请管道,才去fork子进程
1:无名管道有大小限制(4096B), 只要有空位,就可以往里面写数据,--- -- 不能保证数据的原子性
  写满后只能等到有数据被读出才能继续写入
2: 读数据是一定要读到数据才能返回的,否则就会等待
3:只有确定不再需要使用该管道的读或者写功能才能关闭close, 否则关了后就没法再open使用
4:全部进程中必须有一个fd[0]是没有关闭的,才能write进数据; 
  如果fd[0]全关了,write的时候内核会发一个信号 SIGPIPE, 进程对于SIGPIPE的默认操作是终止进程
  实例:

  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <stdlib.h>  
  4. #include <signal.h>  
  5.   
  6. void sig_isr(int sig)  
  7. {  
  8.     printf("catch a SIGPIPE %d \n", sig);  
  9.     //exit(0);  
  10. }  
  11.   
  12.   
  13. int main(void)  
  14. {  
  15.     pid_t pid;  
  16.     int fd[2];  
  17.     char buf[100];  
  18.       
  19.     if(pipe(fd) == -1)  
  20.     {  
  21.         perror("pipe error");  
  22.         exit(1);  
  23.     }  
  24.     printf("fd[0] = %d , fd[1]= %d\n", fd[0], fd[1]); //输出3,4。按顺序1,2被用了  
  25.       
  26.     if((pid = fork())< 0)  
  27.     {  
  28.         perror("fork error");  
  29.         exit(1);  
  30.     }  
  31.     else if(pid == 0)// read  
  32.     {  
  33.         // 读0写1 -- read fd[0] , write [1];  
  34.         close(fd[1]);// 写端关闭  
  35.           
  36.         printf("ready to read...\n");  
  37.         read(fd[0], buf, 100); // 等待  
  38.         printf("%s \n", buf);  
  39.         /*如果上面没有read等待主进程的write,就关闭了f[0] 
  40.         那write的时候内核会发一个信号 SIGPIPE, 进程对于SIGPIPE的默认操作是终止进程*/  
  41.         close(fd[0]);  
  42.         _exit(0);     
  43.     }  
  44.     else // write  
  45.     {     
  46.         signal(SIGPIPE , sig_isr);  
  47.         sleep(1);// for check read's hangup  
  48.         close(fd[0]);//进程间的通信,关闭不需要的,留下的在同一个管道里通信。  
  49.         printf("start write\n");  
  50.         write(fd[1], "hello world \n", 100);  
  51.         printf("end write\n");  
  52.         close(fd[1]);  
  53.         wait(NULL);  
  54.         printf("exit\n");  
  55.         exit(0);  
  56.     }  
  57. }  
有名管道(FIFO ,named pipe)

FIFO 是有一个具体的文件的

mkfifo FIFO -m 0666 --- shell指令去创建
mkfifo("path", 0666) --使用函数去创建,mode&~umask

操作:open / close /read / write
是可以在任意两个进程中通信

open(“path” , )
O_RDONLY 
O_WRONLY
O_RDWR  (FIFO不要用RDWR)
| O_APPEND  (和wr一起用,追加)
| O_TRUNC   (和wr一起用,覆盖,直接清空后再写入,对于FIFO或者设备文件无效)
|O_CREAT|O_EXCL (如果已经存在,会返回失败; FIFO不能用open里面的CREAT创建)
|O_NONBLOCK 
  读写方式|写的方式 |创建并检查 |不阻塞

open(fifo , O_WRONLY|O_NONBLOCK)   看下能否以只写方式打开,不能就马上返回一个失败,比如在没有进程用只读方式打开时候,就会失败

1:open(fifo, O_RDONLY); 
  open(fifo, O_WRONLY);
不管先运行哪个,都会等另一个进程把对应连接打开时候才open结束
 reader 的 open会等到writer的open  运行起来才open结束,
 反之亦然

2:open(fifo, O_RDONLY|O_NONBLOCK );  就不等待writer打开文件了

3:open(fifo , O_WRONLY|O_NONBLOCK):
如果没有reader打开该管道文件的话,就直接报错,退出进程
用perror去抓信息,得到的会是No such device or address
注意:
1:管道有大小限制(4096B), 在写入数据之前,会先判断管道大小是否足够,若不够就不会写入 -- 保证了数据的原子性
  写满后只能等到有数据被读出才能继续写入
2: read读数据是一定要读到数据才能返回的,否则就会等待
3:全部进程中必须有一个reader是没有关闭的,才能write进数据; 
    如果reader全关了,write的时候内核会发一个信号 SIGPIPE, 进程对于SIGPIPE的默认操作是终止进程
4:如果writer设置成非阻塞, 就必须先运行reader,否则无法通信,见open(fifo , O_WRONLY|O_NONBLOCK):

unlink()删除已经不再需要使用的文件,避免造成垃圾文件,对应的是mkfifo创建

实例:

fifoReader.c

  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <fcntl.h>  
  4. #include <sys/types.h>  
  5. #include <sys/stat.h>  
  6. #include <string.h>  
  7.   
  8. #define FIFO "/root/c/process/ififo"  
  9.   
  10. int main(void)  
  11. {  
  12.     int fd;  
  13.     char buf[128];  
  14.   
  15.     if(mkfifo(FIFO, 0666))//创建管道文件  
  16.     {  
  17.          perror("Mkfifo error");  
  18.     }  
  19.     printf("open for reading... \n");  
  20. //  fd=open(FIFO,O_RDONLY);//阻塞  
  21.     fd=open(FIFO,O_RDONLY|O_NONBLOCK);//非阻塞  
  22.     /* 
  23.     1:open(fifo, O_RDONLY);  
  24.            open(fifo, O_WRONLY); 
  25.             不管先运行哪个,都会等另一个进程把对应连接打开时候才open结束 
  26.               reader 的 open会等到writer的open  运行起来才open结束, 
  27.               反之亦然 
  28.         2:open(fifo, O_RDONLY|O_NONBLOCK );  就不等待writer打开文件了 
  29.         3:open(fifo , O_WRONLY|O_NONBLOCK): 
  30.          如果没有reader打开该管道文件的话,就直接报错,退出进程 
  31.          用perror去抓信息,得到的会是No such device or address 
  32.         得先运行reader 
  33.     */  
  34.     printf("opened ... \n");  
  35.     if(fd<0)  
  36.     {  
  37.         perror("Failed to open fifo:");  
  38.         return -1;  
  39.     }  
  40.   
  41.     while(1)  
  42.     {  
  43.         int count;  
  44.         count=read(fd,buf,127);  
  45.         //要用底层io。read()会返回实际读到的字节数  
  46.         if(count>0)  
  47.         {  
  48.             buf[count]=0;//结束符,也可以='\0';  
  49.             printf("fifoReader receive a string:%s\n",buf);  
  50.         }  
  51.         if(strncmp(buf,"exit",4)==0)  
  52.         {  
  53.             break;  
  54.         }  
  55.     }  
  56.     close(fd);    
  57.     return 0;  
  58. }  

fifoWriter.c
  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <fcntl.h>  
  4. #include <sys/types.h>  
  5. #include <sys/stat.h>  
  6. #include <string.h>  
  7. #include <signal.h>  
  8.   
  9. #define FIFO "/root/c/process/ififo"  
  10. int main(void)  
  11. {  
  12.     int fd;  
  13.     char buf[128];  
  14.   
  15.     if(mkfifo(FIFO, 0666))  
  16.     {  
  17.         perror("Mkfifo error");  
  18.     }  
  19.     printf("open for writing ... \n");  
  20.     // fd=open(FIFO,O_WRONLY);// 阻塞  
  21.     fd=open(FIFO,O_WRONLY|O_NONBLOCK);// 如果写端设置成非阻塞,不能先于读端运行,否则 open失败  
  22.     printf("opened... \n");  
  23.     if(fd<0)  
  24.     {  
  25.         perror("Failed to open fifo:");  
  26.         return -1;  
  27.     }  
  28.       
  29.     while(1)  
  30.     {  
  31.         fgets(buf,128,stdin);//标准输入内容  
  32.         write(fd,buf,strlen(buf));//把缓存写入  
  33.         if(strncmp(buf,"exit",4)==0)  
  34.         {  
  35.             break;  
  36.         }  
  37.     }  
  38.     close(fd);  
  39.     unlink(FIFO);     
  40.     return 0;  
  41. }  

区别:

无名管道
1: 亲缘关系进程中
2:没有一个具体的文件 
3:调用write的时候必须保证有个fd[0]是没有closed 
4:pipe 在fork前 ( 申请管道并打开)
5:不保证写入数据的原子性


有名管道
1: 任意两个
2:具体文件
3: 调用write的时候必须保证有个读端(RDONLY的方式)是没有closed 
4:mkfifo  (申请)   
open(path, O_RDONLY)  阻塞, read 是阻塞的,会等有数据可读才返回
open(path,O_RDONLY | O_NONBLOCK) 不阻塞, read也不阻塞,没有数据返回是0
5:保证写入数据的原子性
6:有名管道文件不能在window中存在
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值