【进程间通信】:管道通信/有名/无名

本文详细介绍了进程间通信的多种方式,包括管道(有名和无名)、信号量、共享内存和套接字。重点讲解了管道的工作原理,如半双工和全双工特性,并通过实例演示了有名管道和无名管道的创建及使用。此外,还提到了无名管道仅限于父子进程间的通信,以及管道通信中可能遇到的问题,如阻塞和异常。最后,文章讨论了 dup 函数、文件描述符复制以及标准输入输出的重定向等概念。
摘要由CSDN通过智能技术生成

进程间通信的方式:

  • 管道 (半双工(只能收或者发,不能同时) ,全双工(同步进行,同发同收)
  • 信号量
  • 共享内存
  • 消息队列
  • 套接字
  • 管道: 有名管道和无名管道
    有名管道:可以在任意进程间通信
    无名管道:仅在父子进程间通信
  • 定义:
    从一个进程链接数据流到另外一个进程
    说人话:一个进程的输出通过某种介质作为另一个进程的输入
    这个介质就是管道。这也是需要管道的原因。
    命令的写法:cmd1 | cmd2
    比如shell 让标准输入和标准输出两个命令通果管道显示在终端屏幕上:
    cmd1 标准输入的命令(键盘)
    cmd1 标准输出传给 cmd2 ,作为cmd2的标准输入
    cmd2 标准输出到屏幕
    如下图:请添加图片描述
  • 管道通信:如果需要程序实现,需要两个函数(popen()和pclose())来实现两个进程之间的数据传递。
    command :要运行的程序名和相应的参数
    open_mode:r / w 权限
    r : 被输出的程序可以被输出程序使用,输出程序利用popen返回的FILE*文件流指针,使用fread来读取被输出程序的输出。
    w: 输出程序通过fwrite 向被输出程序发送数据。而被输出程序从标准输入读取数据。【它不知道这口饭刚从别人嘴里吐出来。放在盘子里。】
    【接盘侠,可以理解为从婚介所得到一个其他人吐出来的二手货】
#include<stdio.h>
FILE *popen(const char* command,const char* open_mode);
int pclose(FILE *stream_to_close);

popen() :允许一个程序将另外一个程序做为新进程启动。
也就是一个程序的输出命令作为了另一个程序的输入
pclose() : 只在popen启动的进程结束后返回。返回值是所关闭的文件流所在的进程的退出码。如果父进程提前获取了该进程的退出码,那么该进程极其资源被回收。其返回值为-1或error。
也就是pclose必须在父进程获取该进程退出码之前执行。

例如:ps -ef 输出 | 输入grep “main”
请添加图片描述

            出现一下问题:
             1.  管道必须读写进程同时 open,否则会阻塞
             2. 如果管道没有数据,那么read ,阻塞
             3.  管道的写端关闭,读read返回值为0
             4. 管道的读端关闭,写会产生异常(发送SIGPIPE)
              (女朋友挂断电话,你还一个劲说话有啥用?)
#include<signal.h>
void fun(int sig)
{
        printf("sig =%d",sig);
}
int main()
{
    signal(SIGPIPE,fun);

请添加图片描述

  • 创建有名管道
    mkfifo FIFO (fifo 可以随便起)

touch a.c b.c
特殊之处:打开文件管道文件,会在内存中开辟一片空间,会将写入的数据写入内存中。不论有名管道还是无名管道

  • a.c文件
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
int main()
{
	int fdw = open("fifo", O_WRONLY);
	if (fdw == -1)
	{
		exit(-1);
	}
	char buff[128] = { 0 };
	fgets(buff, 128, stdin);
	write(fdw, buff, strlen(buff) - 1);
	close(fdw);
	exit(0);
}
  • b.c文件

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>

int main()
{
	int fdr = open("fifo", O_RDONLY);
	if (fdr == -1)
	{
		exit(1);
	}
	printf("fdr =%d\n", fdr);
	char buff[128] = { 0 };
	int num = read(fdr, buff, 127);
	printf("buff =%s\n", buff);
	close(fdr);
	exit(0);
 }

请添加图片描述

  • 改进:(连续发送数据,和接收数据)
    管道中没有数据会阻塞住(只要不关闭管道)
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
int main()
{
	int fdw = open("fifo", O_WRONLY);
	if (fdw == -1)
	{
		exit(-1);
	}
	while(1){
	char buff[128] = { 0 };
	fgets(buff, 128, stdin);
    if(strncmp(buff,"end",3)==0 )
    {
     break;
     }
	write(fdw, buff, strlen(buff) - 1);
	}
	close(fdw);
	exit(0);
}
  • b.c文件

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>

int main()
{
	int fdr = open("fifo", O_RDONLY);
	if (fdr == -1)
	{
		exit(1);
	}
	printf("fdr =%d\n", fdr);
	while(1){
	char buff[128] = { 0 };
	int num = read(fdr, buff, 127);
	if(num == 0)  //读到的数据为0
	{
	break;
	}
	printf("buff =%s\n", buff);
	}
	close(fdr);
	exit(0);
 }

请添加图片描述
无名管道创建
man pipe请添加图片描述
通过pipe打开管道文件,直接将管道的文件描述符返回
会用fork()产生一个子进程,(因此父进程负责写,子进程负责读)
必须父子进程均关闭,该文件才关闭ca。(教室最后一个人走了,才算真的关闭)

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
int main()
{
	int fd[2];
	if (pipe(fd) == -1)  //fd[0] 读,fd[1]写
	{
		exit(1);
	}
	printf("fd[0] = %d,fd[1] = %d\n", fd[0], fd[1]);

    pid_t pid =fork();
    if(pid == -1)
    {
            exit(0);
    }
    if(pid == 0)
    {
      close(fd[1]);
      char buff[128] ={0};
      read(fd[0],buff,127);
      printf("child read :%s\n",buff);
      close(fd[0]);
    }
    else
    {
            close(fd[0]);
            write(fd[1],"abc",3);
            close(fd[1]);

    }
	exit(0);
 }

请添加图片描述

  • 面试会问
    请添加图片描述
    dup(3,1) 将3的文件描述符复制到1的位置
    ls>a.test 文件重定向 (追加和覆盖)
    因为标准输入输出已经被a.txt 覆盖,因此就没有标准输出和标准输入了。因此hello打印再a.txt中
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
int main()
{
	int fd = open("a.txt", O_WRONLY | O_CREAT, 0600)
	{
		if (fd == -1)
		{
			printf("open a.txt filed\n");
			exit(1);
		}
		dup2(fd, 1);
		dup2(fd, 2);
	}
	printf("hello\n"); //因为标准输入输出已经被a.txt 覆盖,因此就没有标准输出和标准输入了。因此hello打印再a.txt中
	exit(0);
}

请添加图片描述

管道的实现:
请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值