进程间通信:
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的默认操作是终止进程
实例:
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <signal.h>
- void sig_isr(int sig)
- {
- printf("catch a SIGPIPE %d \n", sig);
- //exit(0);
- }
- int main(void)
- {
- pid_t pid;
- int fd[2];
- char buf[100];
- if(pipe(fd) == -1)
- {
- perror("pipe error");
- exit(1);
- }
- printf("fd[0] = %d , fd[1]= %d\n", fd[0], fd[1]); //输出3,4。按顺序1,2被用了
- if((pid = fork())< 0)
- {
- perror("fork error");
- exit(1);
- }
- else if(pid == 0)// read
- {
- // 读0写1 -- read fd[0] , write [1];
- close(fd[1]);// 写端关闭
- printf("ready to read...\n");
- read(fd[0], buf, 100); // 等待
- printf("%s \n", buf);
- /*如果上面没有read等待主进程的write,就关闭了f[0]
- 那write的时候内核会发一个信号 SIGPIPE, 进程对于SIGPIPE的默认操作是终止进程*/
- close(fd[0]);
- _exit(0);
- }
- else // write
- {
- signal(SIGPIPE , sig_isr);
- sleep(1);// for check read's hangup
- close(fd[0]);//进程间的通信,关闭不需要的,留下的在同一个管道里通信。
- printf("start write\n");
- write(fd[1], "hello world \n", 100);
- printf("end write\n");
- close(fd[1]);
- wait(NULL);
- printf("exit\n");
- exit(0);
- }
- }
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
- #include <unistd.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <string.h>
- #define FIFO "/root/c/process/ififo"
- int main(void)
- {
- int fd;
- char buf[128];
- if(mkfifo(FIFO, 0666))//创建管道文件
- {
- perror("Mkfifo error");
- }
- printf("open for reading... \n");
- // fd=open(FIFO,O_RDONLY);//阻塞
- fd=open(FIFO,O_RDONLY|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
- 得先运行reader
- */
- printf("opened ... \n");
- if(fd<0)
- {
- perror("Failed to open fifo:");
- return -1;
- }
- while(1)
- {
- int count;
- count=read(fd,buf,127);
- //要用底层io。read()会返回实际读到的字节数
- if(count>0)
- {
- buf[count]=0;//结束符,也可以='\0';
- printf("fifoReader receive a string:%s\n",buf);
- }
- if(strncmp(buf,"exit",4)==0)
- {
- break;
- }
- }
- close(fd);
- return 0;
- }
fifoWriter.c
- #include <unistd.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <string.h>
- #include <signal.h>
- #define FIFO "/root/c/process/ififo"
- int main(void)
- {
- int fd;
- char buf[128];
- if(mkfifo(FIFO, 0666))
- {
- perror("Mkfifo error");
- }
- printf("open for writing ... \n");
- // fd=open(FIFO,O_WRONLY);// 阻塞
- fd=open(FIFO,O_WRONLY|O_NONBLOCK);// 如果写端设置成非阻塞,不能先于读端运行,否则 open失败
- printf("opened... \n");
- if(fd<0)
- {
- perror("Failed to open fifo:");
- return -1;
- }
- while(1)
- {
- fgets(buf,128,stdin);//标准输入内容
- write(fd,buf,strlen(buf));//把缓存写入
- if(strncmp(buf,"exit",4)==0)
- {
- break;
- }
- }
- close(fd);
- unlink(FIFO);
- return 0;
- }
区别:
无名管道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中存在
本文深入探讨了进程间通信(IPC)的基本概念和技术,包括无名管道(PIPE)和有名管道(FIFO)的特点与应用场景。详细介绍了这两种管道的工作原理、创建方式、读写操作及其注意事项。
553

被折叠的 条评论
为什么被折叠?



