Linux进程间通信的方法
一、管道通信
管道的特点
- 1.管道是一个字节流
- 2.管道是单向的
- 3.管道的容量是有限的
- 4.管道一次写入数量最大为PIPE_BUF。多进程同时写入时,如果超过了这个数量,可能会发生数据混合。
- 5.当管道中不存在数据时,read操作会阻塞(如果管道写端已经关闭,read操作会返回0)
1.标准流管道
-
1. 打开关闭标准流管道:
-
打开操作
使用popen函数创建。一般用于父子进程间的通信。
- 输入:1.shell指令 command,指定打开的程序, 2.管道流的打开方法,指定为w或r
- 返回: 1.成功:标准输入输出流, 2.失败 NULL
- popen
popen()函数1.创建了一个管道,2.然后创建了一个子进程来执行shell,3.而shell又创建了一个子进程来执行command字符。mode参数示一个字符串,它确定调用进程是从管道中读取数据mode 为r,还是将数据写入管道中,mode是w。
mode的取值,确定了所执行的命令的标准输出连接到管道的写入端还是将其标准输入连接到管道的读取端。
-
关闭操作
- 随机管道流式FILE*类型,但关闭不能使用fclose(),必须使用 pclose()函数。
- pclose的输出流,默认是块缓冲模式
- pclose执行后,进程会进入阻塞状态,直到popen开启的进程结束。
- 成功时,pclose返回新进程的退出状态,失败时返回-1 -
2.数据的读写
-
在调用进程中,管道流的读写使用fread()/fwrite()进行
-
在开启的新进程中,管道流的读写使用scanf()和printf()进行
-
3.使用流程
//1.创建标准流管道,将其设置为只读模式
FILE* pipe = popen("./hello","r");
//2.从pipe中读取数据
char msg[100] = {
0};
int ret = fread(msg,1,100,pipe);
//3.关闭流
pclose(pipe);
//hello.c向pipe中写入数据的方法
printf("hello,world");
2.无名管道PIPE
- 特点:
- 只能在亲缘关系进程间进行通信(父子或兄弟)
- 半双工
- 无名管道是特殊的文件,可以用read\write读写,只能在内存中
- 创建方法
无名管道是利用文件描述符来创建管道文件,创建成功后,会分别传回管道文件的读端和写端的文件描述符。因此,只可以用于共享文件描述符的进程之间的通信。
一般使用第二种形式比较多一些;- 传入参数 int数组,大小为2,用于接收返回的管道文件描述符,pipefd[0]为读端,pipedf[1]为写端
- 返回 正常返回0,错误返回-1.
- 使用第三种形式时,如果flags指定0,和第二种一样。
flags 可以指定为
O_NONBLOCK 设定为非阻塞模式。
O_DIRECT 设定为包传输模式,每次read/write会向管道中读取/写入一个数据包。(连续发送数据时不会粘在一起)
- 读取和写入操作
正常使用read/write对文件描述符进行操作即可 - 关闭操作
使用close操作来关闭管道的文件描述符即可。
需要注意的是,- 管道的写端先关闭时,读端会返回0,并不会报错,此时根据读端返回的数值进行管道的关闭即可。
- 管道的读端先关闭,则写端进程会收到到SIGPIPE信号,进程异常终止;如果写端处理了SIGPIPE信号,则会返回一个负值,表示管道读端已经关闭。
- 使用流程
//1.创建无名管道文件
int fdp[2] = {
-1};
int ret = pipe(fdp);
if(-1 == ret) {
perror("pipe");
exit(-1)
}
//2.创建子进程
char msg[100]={
0};
ret = fork();
if(ret){
if(ret = -1) exit(-1);
//3.关闭父进程写端,使用读端读取子进程的数据
close(fd[1]);
//4.读取数据
read(fd[0],msg,100);
printf("msg:%s\n",msg);
wait(NULL);
//5.关闭读端
close(fd[0]);
}else {
//3.关闭子进程读端,使用写端
close(fd[0]);
//4.写入数据
write(fd[1]."hello,world",11);
//5.关闭写端
close(fd[1]);
return</