进程间的通信-管道

 1.什么是进程间的通信(解决什么问题)
        父子进程(数据的收发)
        两个毫无关联的进程之间的通信(数据的收发)
   2.有哪些通信方式
        管道:无名管道和有名管道
        信号:
        共享内存:
        消息队列:
        信号量:
        套接字编程:
   3.管道
        3.1 无名管道
              (1)相关的接口函数
                 创建无名管道
                   int pipe(int fildes[2]);
                        返回值:成功  0  失败 -1
                          参数:fildes --》存放的是文件描述符
                                fildes[0] --》读端的文件描述符
                                fildes[1] --》写端的文件描述符
              (2)无名管道的特点
                    见图示

 

         3.2  有名管道
              (1)相关的接口函数
                  第一步:创建有名管道
                     int mkfifo(const char *pathname, mode_t mode);
                          返回值: 成功 0  失败 -1
                            参数:pathname --》你要创建的有名管道的路径名
                                  mode --》权限 0777
                  第二步:open打开你刚才创建的有名管道
                  第三步:使用read/write往有名管道中读写数据
                  第四步:关闭有名管道
                            close
               (2)有名管道的特点
                   特点1: 有名管道只能在纯粹的linux环境中创建,不能在共享路径下创建(管道文件是属于linux系统特有的一种文件类型,windows不支持该文件类型)
                   特点2:进程1写入hello到有名管道中,然后退出了
                          进程2运行,读取有名管道中的内容,发现读取不了
                   特点3:管道不能使用lseek()去设置读写偏移

                 
         3.3  有名管道和无名管道的区别
                  区别1:有名管道创建成功以后会在系统中产生管道文件
                         无名管道创建成功以后没有管道文件,只有文件描述符
                  区别2:有名管道没有固定的读写端,可以随意读写
                         无名管道有固定的读写端,不能用错
                  区别3:有名管道既能用于血缘关系的进程间通信,也能用于没有任何血缘关系的进程间通信
                         无名管道只能用于血缘关系的进程间通信

 无名管道弄错啦读写端

#include "myhead.h"

//父子进程采用无名管道单向通信
//儿子给父亲发送信息

int main()
{
	char buf[100];
	int fd[2];
	//创建一个无名管道
	int ret=pipe(fd);
	if(ret==-1)
	{
		printf("创建无名管道失败!\n");
		return -1;
	}
	//生个仔
	pid_t id=fork();
	if(id>0)  //父
	{
		while(1)
		{
			//从无名管道的读端去读取内容
			read(fd[1],buf,100); //用错了文件描述符,导致read不会阻塞了
			printf("儿子发送过来的信息是:%s\n",buf);
		}
	}
	else if(id==0) //子 
	{
		while(1)
		{
			bzero(buf,100);
			printf("请输入要发送给老爸的信息!\n");
			scanf("%s",buf);
			//使用写端把buf写入到无名管道中
			write(fd[0],buf,strlen(buf));  //弄错了写端的文件描述符
		}
		
	}
	
}

父子进程采用无名管道单向通讯

#include "myhead.h"

//父子进程采用无名管道单向通信
//儿子给父亲发送信息

int main()
{
	char buf[100];
	int fd[2];
	//创建一个无名管道
	int ret=pipe(fd);
	if(ret==-1)
	{
		printf("创建无名管道失败!\n");
		return -1;
	}
	//生个仔
	pid_t id=fork();
	if(id>0)  //父
	{
		while(1)
		{
			//从无名管道的读端去读取内容
			read(fd[0],buf,100);
			printf("儿子发送过来的信息是:%s\n",buf);
		}
	}
	else if(id==0) //子 
	{
		while(1)
		{
			bzero(buf,100);
			printf("请输入要发送给老爸的信息!\n");
			scanf("%s",buf);
			//使用写端把buf写入到无名管道中
			write(fd[1],buf,strlen(buf));
		}
		
	}
	
	close(fd[0]);
	close(fd[1]);
	return 0;
	
}

一个无名管道实现父子进程单向通讯

#include "myhead.h"

//父子进程采用无名管道双向通信


int main()
{
	char buf[100];
	char otherbuf[100];
	int fd1[2];
	//创建一个无名管道
	int ret=pipe(fd1);
	if(ret==-1)
	{
		printf("创建无名管道失败!\n");
		return -1;
	}
	
	//生个仔
	pid_t id=fork();
	if(id>0)  //父
	{
		while(1)
		{
			bzero(buf,100);
			bzero(otherbuf,100);
			//从无名管道的读端去读取内容
			read(fd1[0],buf,100); 
			printf("儿子发送过来的信息是:%s\n",buf);
			//回复信息给儿子
			printf("请输入要回复给儿子的信息!\n");
			scanf("%s",otherbuf);
			write(fd1[1],otherbuf,strlen(otherbuf));
			sleep(1); //目的为了防止父进程写入管道的信息,立马被父进程自己读取出来了
		}
	}
	else if(id==0) //子 
	{
		while(1)
		{
			bzero(buf,100);
			bzero(otherbuf,100);
			printf("请输入要发送给老爸的信息!\n");
			scanf("%s",buf);
			//使用写端把buf写入到无名管道中
			write(fd1[1],buf,strlen(buf)); 
			sleep(1); //目的为了防止子进程写入管道的信息,立马被子进程自己读取出来了
			//从管道里面读取信息
			read(fd1[0],otherbuf,100);
			printf("父亲发送给我的信息是:%s\n",otherbuf);
			
		}
		
	}
	
}

两个无名管道实现父子进程的双向通讯

#include "myhead.h"

//父子进程采用无名管道双向通信


int main()
{
	char buf[100];
	char otherbuf[100];
	int fd1[2];
	int fd2[2];
	//创建两个无名管道
	int ret=pipe(fd1);
	if(ret==-1)
	{
		printf("创建无名管道失败!\n");
		return -1;
	}
	ret=pipe(fd2);
	if(ret==-1)
	{
		printf("创建无名管道失败!\n");
		return -1;
	}
	
	//生个仔
	pid_t id=fork();
	if(id>0)  //父
	{
		while(1)
		{
			bzero(buf,100);
			bzero(otherbuf,100);
			//从第一个无名管道的读端去读取内容
			read(fd1[0],buf,100); 
			printf("儿子发送过来的信息是:%s\n",buf);
			//回复信息给儿子
			printf("请输入要回复给儿子的信息!\n");
			scanf("%s",otherbuf);
			//把信息写入到第二个无名管道中
			write(fd2[1],otherbuf,strlen(otherbuf));
		}
	}
	else if(id==0) //子 
	{
		while(1)
		{
			bzero(buf,100);
			bzero(otherbuf,100);
			printf("请输入要发送给老爸的信息!\n");
			scanf("%s",buf);
			//使用写端把buf写入到第一个无名管道中
			write(fd1[1],buf,strlen(buf)); 
			//从第二个无名管道中读取内容
			read(fd2[0],otherbuf,100);
			printf("我老爸回复的信息是:%s\n",otherbuf);
		}
		
	}
	
}

有名管道单向通讯在父子进程之间通讯

#include "myhead.h"

int main()
{
	int fd;
	char buf[100];
	//由于有名管道不能重复创建
	//先判断管道文件是否存在
	if(access("/home/gec/friend",F_OK)==0) //说明管道文件已经存在
	{
		//直接打开管道文件
		fd=open("/home/gec/friend",O_RDWR);
		if(fd==-1)
		{
			perror("打开管道文件失败!\n");
			return -1;
		}
	}
	else  //管道文件不存在
	{
		//创建一个有名管道
		int ret=mkfifo("/home/gec/friend",0777);
		if(ret==-1)
		{
			perror("创建有名管道失败!\n"); //perror
			return -1;
		}
		//再来打开
		fd=open("/home/gec/friend",O_RDWR);
		if(fd==-1)
		{
			perror("打开管道文件失败!\n");
			return -1;
		}
	}
	
	//创建一个子进程
	pid_t id=fork();
	if(id>0)  //父进程
	{
		//从有名管道中读取内容
		while(1)
		{
			read(fd,buf,100);
			printf("儿子发送的信息是:%s\n",buf);
		}
	}
	else if(id==0)  //子进程
	{
		while(1)
		{
			bzero(buf,100);
			printf("请输入要发送给父亲的信息!\n");
			scanf("%s",buf);
			//使用刚才打开的有名管道,把信息发送给父进程
			write(fd,buf,strlen(buf));
		}
	}
	
	
}

两个进程没有任何血缘关系利用有名管道双向通讯

#include "myhead.h"

//p1和p2双向通信


int main()
{
	int fd;
	char buf[100];
	char rbuf[100];
	printf("p1进程运行了,是个独立的进程!\n");
	//由于有名管道不能重复创建
	//先判断管道文件是否存在
	if(access("/home/gec/friend",F_OK)==0) //说明管道文件已经存在
	{
		//直接打开管道文件
		fd=open("/home/gec/friend",O_RDWR);
		if(fd==-1)
		{
			perror("打开管道文件失败!\n");
			return -1;
		}
	}
	else  //管道文件不存在
	{
		//创建一个有名管道
		int ret=mkfifo("/home/gec/friend",0777);
		if(ret==-1)
		{
			perror("创建有名管道失败!\n"); //perror
			return -1;
		}
		//再来打开
		fd=open("/home/gec/friend",O_RDWR);
		if(fd==-1)
		{
			perror("打开管道文件失败!\n");
			return -1;
		}
	}
	
	//循环发送信息给p2
	while(1)
	{
		bzero(buf,100);
		bzero(rbuf,100);
		printf("请输入要发送给p2的信息!\n");
		scanf("%s",buf);
		//通过有名管道发送给p2
		write(fd,buf,strlen(buf));
		sleep(1);
		//从管道中读取p2回复的信息
		read(fd,rbuf,100);
		printf("p2回复的信息是:%s\n",rbuf);
	}
}
#include "myhead.h"

//双向通信

int main()
{
	int fd;
	char buf[100];
	char rbuf[100];
	printf("p2进程运行了,是个独立的进程!\n");
	//由于有名管道不能重复创建
	//先判断管道文件是否存在
	if(access("/home/gec/friend",F_OK)==0) //说明管道文件已经存在
	{
		//直接打开管道文件
		fd=open("/home/gec/friend",O_RDWR);
		if(fd==-1)
		{
			perror("打开管道文件失败!\n");
			return -1;
		}
	}
	else  //管道文件不存在
	{
		//创建一个有名管道
		int ret=mkfifo("/home/gec/friend",0777);
		if(ret==-1)
		{
			perror("创建有名管道失败!\n"); //perror
			return -1;
		}
		//再来打开
		fd=open("/home/gec/friend",O_RDWR);
		if(fd==-1)
		{
			perror("打开管道文件失败!\n");
			return -1;
		}
	}
	
	//循环从管道中读取信息
	while(1)
	{
		bzero(buf,100);
		bzero(rbuf,100);
		//通过有名管道读取p1发送的信息
		read(fd,buf,100);
		printf("p1发送给我的信息是:%s\n",buf);
		//回复信息给p1
		printf("请输入要回复给p1的信息!\n");
		scanf("%s",rbuf);
		write(fd,rbuf,strlen(rbuf));
		sleep(1); //防止自己写的内容,自己立马读取出来了
	}
}

两个没有血缘关系的进程之间利用有名管道单向通讯

#include "myhead.h"

//p1进程发送信息给p2--》单向通信

int main()
{
	int fd;
	char buf[100];
	printf("p1进程运行了,是个独立的进程!\n");
	//由于有名管道不能重复创建
	//先判断管道文件是否存在
	if(access("/home/gec/friend",F_OK)==0) //说明管道文件已经存在
	{
		//直接打开管道文件
		fd=open("/home/gec/friend",O_RDWR);
		if(fd==-1)
		{
			perror("打开管道文件失败!\n");
			return -1;
		}
	}
	else  //管道文件不存在
	{
		//创建一个有名管道
		int ret=mkfifo("/home/gec/friend",0777);
		if(ret==-1)
		{
			perror("创建有名管道失败!\n"); //perror
			return -1;
		}
		//再来打开
		fd=open("/home/gec/friend",O_RDWR);
		if(fd==-1)
		{
			perror("打开管道文件失败!\n");
			return -1;
		}
	}
	
	//循环发送信息给p2
	while(1)
	{
		bzero(buf,100);
		printf("请输入要发送给p2的信息!\n");
		scanf("%s",buf);
		//通过有名管道发送给p2
		write(fd,buf,strlen(buf));
	}
}

 

#include "myhead.h"

//p1进程发送信息给p2--》单向通信

int main()
{
	int fd;
	char buf[100];
	printf("p2进程运行了,是个独立的进程!\n");
	//由于有名管道不能重复创建
	//先判断管道文件是否存在
	if(access("/home/gec/friend",F_OK)==0) //说明管道文件已经存在
	{
		//直接打开管道文件
		fd=open("/home/gec/friend",O_RDWR);
		if(fd==-1)
		{
			perror("打开管道文件失败!\n");
			return -1;
		}
	}
	else  //管道文件不存在
	{
		//创建一个有名管道
		int ret=mkfifo("/home/gec/friend",0777);
		if(ret==-1)
		{
			perror("创建有名管道失败!\n"); //perror
			return -1;
		}
		//再来打开
		fd=open("/home/gec/friend",O_RDWR);
		if(fd==-1)
		{
			perror("打开管道文件失败!\n");
			return -1;
		}
	}
	
	//循环从管道中读取信息
	while(1)
	{
		bzero(buf,100);
		//通过有名管道读取p1发送的信息
		read(fd,buf,100);
		printf("p1发送给我的信息是:%s\n",buf);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hqb_newfarmer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值