一、管道

二、 信号

三、共享内存

四、消息队列

五、信号量

进程间的通信可分为 传统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;
}

未完待续……

Logo

更多推荐