C语言进程间通信

来源:互联网 发布:数据分析师工资 编辑:程序博客网 时间:2024/06/10 20:29

进程间通信:
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 hangupclose(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 ,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

#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中存在

0 0
原创粉丝点击