Linux进程间管道通信

无名管道:

无名管道的特点:


只能用于具有亲缘关系间的通信。【父子进程 或 兄弟进程】

半双工通信。【只能由一方发送,另一方接收】

通信端口固定。【fd[0]:读管道 ,fd[1]:写管道】

管道也是一种特殊的文件,对于它的读写,也可以使用普通的read(),write()函数。

管道不属于任何文件系统,只存在于内存中。

在这里插入图片描述

无名管道的创建

无名管道是基于 文件描述符 的通信方式,当一个管道被建立时,它会创建两个文件描述符:fd[0]、fd[1].
fd[0]:读文件描述符,用于固定读管道
fd[1]:写文件描述符,用于固定写管道

在这里插入图片描述

无名管道的相关函数


头文件:#include<unistd.h>

函数名:pipe

参数:int  pipefd[]  :包含两个元素的整型数组,存 

                                  放管道对应的文件描述符

返回值:成功--> 0   失败--> -1


int  pipe(int  pipefd[]);


 pipe函数创建的管道两端处于同一个进程中。由于管道主要是用于不同进程间的通信,所以首先会fork()一个子进程,该子进程会继承父进程所创建的管道。此时父子进程就都拥有了一个管道,所以会产生两个fd[0],fd[1]。

  根据需要,若是父进程发消息,子进程收消息。那么久关闭父进程的fd[1],关闭子进程的fd[0]。此时父进程就只有fd[0],子进程也就只有fd[1]了。他们俩就能通过无名管道来进行单向通信。

在这里插入图片描述


同理,若是需要子进程发送数据,父进程接收数据,就关闭对应的文件描述符即可。

举个栗子

在这里插入图片描述


注意事项:

 只有管道的读端存在时,向管道内写入数据才有意义。否则,向管道内写入的数据的进程会收到内核传来的SIGPIPE信号。【通常为Broken Pipe(管道破裂) 错误】

 向管道内写入数据时,Linux不保证写入的原子性,管道缓冲区只要有空间,写进程就会向管道写入数据;若管道已满,则写操作会阻塞等待

 父子进程在运行时,他们的先后次序不能保证。 为确保父子进程已经关闭了相应的文件描述符,可以在两个进程中调用 sleep()函数


【附】上述例子的源码:

#include<stdio.h>

#include<unistd.h>

#include<string.h>



int main(void)

{

pid_t pid = -1;

int pipefd[2];

//创建无名管道

if(0 > pipe(pipefd))

{

perror("pipe error!\n");

return -1;

}

puts("pipe success!");

/*pipe[0]读端 , pipe[1]写端*/

pid = fork();//创建子进程

//判断是否创建成功

if(0 > pid)//pid错误

{

perror("fork error!\n");

return -1;

}

else if(0 < pid)

{

//父进程 发  子进程 收

close(pipefd[0]);//关闭父进程的读端fd[0]

//发送数据

char buf[20] = {0};

//从键盘输入小于20的字符串

gets(buf , sizeof(buf) , stdin);

//将获得的字符串通过管道传递给子进程(pipefd[1]是子进程的接收端)

write(pipefd[1] , buf , strlen(buf));

//关闭父进程的写文件描述符

close(pipefd[1]);

}

else if(0 == pid)

{

//子进程

close(pipefd[1]);//关闭子进程的写端fd[1]

//接收数据

char buf1[20] = {0};

read(pipefd[0] , buf1 , sizeof(buf1));


printf("read data : %s\n" , buf1);

//关闭读端

close(pipefd[0]);


}

return 0;

}


#include <stdio.h>

#include <unistd.h>

#include <string.h>

#include <stdlib.h>

 //-----------------------------------------------示例二--------------------------------------------//

int main()

{

     int fd[2];

 

     int pid;

 

     char readbuf[128];

 

     if(pipe(fd) == -1){

          printf("creat pipe fail\n");

     }

 

     pid = fork();

 

     if(pid < 0){

          printf("creat child fail\n");

     }

     else if(pid > 0){

          printf("this is father\n");

          sleep(3);

          close(fd[0]);

          write(fd[1],"hellow this father",strlen("hellow this father"));

          wait();

     }else{

          printf("this is child\n");

          close(fd[1]);

          read(fd[0],readbuf,128);

          printf("this is from father:%s\n",readbuf);

          exit(0);

     }

     return 0;

}