Linux进程间通信的五种方式
一、管道一、管道二、 信号三、共享内存四、消息队列五、信号量。
·
一、管道
二、 信号
三、共享内存
四、消息队列
五、信号量
进程间的通信可分为 传统unix通信方式 和 System V通信方式 。
传统unix通信方式有两大类:管道和信号。其中管道又细分为:有名管道和无名管道。
无名管道:
无名管道的特点:
- 只能用于具有亲缘关系间的通信。【父子进程 或 兄弟进程】
- 半双工通信。【只能由一方发送,另一方接收】
- 通信端口固定。【fd[0]:读管道 ,fd[1]:写管道】
- 管道也是一种特殊的文件,对于它的读写,也可以使用普通的read(),write()函数。
- 管道不属于任何文件系统,只存在于内存中。
无名管道的创建
无名管道是基于 文件描述符 的通信方式,当一个管道被建立时,它会创建两个文件描述符:fd[0]、fd[1].
fd[0]:读文件描述符,用于固定读管道
fd[1]:写文件描述符,用于固定写管道
无名管道的相关函数
1:pipe()函数.
头文件:#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;
}
未完待续……
更多推荐
已为社区贡献1条内容
所有评论(0)