进程间通信(管道通信)

1.管道通信:
(1)匿名管道:
匿名管道的特点是没有名称,所以用户无法使用open来创建和打开,但是匿名管道进行数据读写的方式和普通文件一样,都是支持read()/write()操作的。

思考:匿名管道在Linux系统下属于文件,但是匿名管道没有名称,请问应该如何创建匿名管道以及对匿名管道进行访问?
回答:Linux系统提供了系统调用接口pipe()来创建匿名管道,用户可以通过man 2 pipe来查阅函数的使用规则。
image

可以看到pipe函数由一个名字叫做pipefd的参数,该参数是一个数组类型,用于存储对管道进行读写的文件描述符,pipefd[0]记录管道读取端的文件描述符,pipefd[1]记录管道写入端的文件描述符。另外,用户把对数据写入到管道之后,数据是会在内核的缓冲区中进行暂存的,直到从管道中读取该数据为止。

思考:可以看到pipe函数调用成功可以得到创建成功的匿名管道关于读取端和写入端的文件描述符,这样两个进程之间就可以通过文件描述符对匿名管道进行访问,但由于匿名管道没有名称,请问匿名管道适合什么样的进程使用?以及进程中什么时候适合创建匿名管道?
回答:由于匿名管道没有名称,所以只适合在有亲缘关系的进程中使用,一般经常用于父子进程之间。
设计一个程序,实现在程序中创建一个子进程,然后父子进程通过匿名管道进行通信,要求子进程发送字符串“Hello Father,I am Child!”,要求父进程把子进程发送的数据输出到终端,然后父子进程退出。

点击查看代码
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>


int main(int argc,char const *argv[]){
    //1.创建匿名管道
    int piped_fd[2] = {0};
    int ret = pipe(piped_fd);
    if(-1 == ret){
        fprintf(stderr,"pipe error,errno:%d,%s",errno,strerror(errno));
        return -1;
    }
    //2.创建子进程,调用fork函数的时候就已经创建子进程
    pid_t child_pid = fork(); 

    if (child_pid > 0)
	{
		//说明是父进程的进程空间
		char recvbuf[30] = {0};
		read(piped_fd[0],recvbuf,sizeof(recvbuf));
        printf("the massage from child is %s\n",recvbuf);
        wait(NULL);
	}
	else if( child_pid == 0)
	{
		//说明是子进程的进程空间
		char sendbuf[30] = "Hello child,I am father";
        write(piped_fd[1],sendbuf,strlen(sendbuf));
	}
	else
	{
		printf("child process fork error\n");
		return -1;
	}

	

	return 0;
}

(2)命名管道 由于匿名管道只适合一对一、并且具有亲缘关系的进程间通信,导致局限性较大,所以Linux系统下还提供了另一种管道,名称叫做命名管道,也可以称为有名管道、具名管道等。 相比于匿名管道而言,命名管道有自己的文件名,可以被open,同样也支持read/write访问。当然,管道文件毕竟不是普通文件,由于管道的特性的原因,所以管道是不支持指定位置读取数据的,也就意味着不能对管道文件进行lseek操作。 访问命名管道的前提是命名管道存在,所以Linux系统中提供了一个名字叫做mkfifo()的函数接口来创建命名管道。 ![image](https://img2024.cnblogs.com/blog/3655216/202508/3655216-20250809172254660-2066395880.png) 注意:如果是新建的管道文件,则需保证创建路径位于Linux系统内,尤其是虚拟机中操作的时候,不可以将管道文件创建在共享文件夹中,因为共享文件夹是windows系统中的路径。 在 /tmp 目录下创建一条命名管道,命名管道的名称用户决定,然后设计两个程序,要求进程A获取当前系统时间(time-->ctime)并写入到命名管道,进程B从命名管道中读取数据并存储在一个名字叫做log.txt的文本中。 processA:
点击查看代码
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#define FIFO_PATH "/tmp/fifo"
int main(int argc,char const *argv[]){
    //1.进程A创建有名管道
    int ret = mkfifo(FIFO_PATH,0777);
    if(-1 == ret){
        fprintf(stderr,"mkfifo error,errno:%d,%s\n",errno,strerror(errno));
        exit(1);
    }
    //2.进程A打开有名管道
    int fifo_fd = open(FIFO_PATH,O_RDWR);
    if(-1 == fifo_fd){
        fprintf(stderr,"open error,errno:%d,%s\n",errno,strerror(errno));
        exit(2);
    }
    //3.进程A获取时间并格式化为字符串,写入管道文件中
    time_t tim = time(NULL);
    char *ptime;
    while(1){
        ptime = ctime(&tim);
        write(fifo_fd,ptime,strlen(ptime));
        sleep(1);
    }
    //4.关闭有名管道
    close(fifo_fd);
    return 0;
    
}
processB:
点击查看代码
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <strings.h>
#define FIFO_PATH "/tmp/fifo"
#define LOG_PATH  "./log.txt"
int main(int argc,char const *argv[]){
    //1.创建log.txt
    int log_fd = open(LOG_PATH,O_RDWR|O_CREAT);
    if(-1 == log_fd){
        fprintf(stderr,"oprn log error,errorno:%d,%s\n",errno,strerror(errno));
        exit(1);
    }
    //2.进程B打开有名管道
    int fifo_fd = open(FIFO_PATH,O_RDWR|O_CREAT);
    if(-1 == fifo_fd){
        fprintf(stderr,"open fifo error,errno:%d,%s\n",errno,strerror(errno));
        exit(2);
    }
    //3.进程B读取有名管道
    char timebuf[126] = {0};
    while(1){
        read(fifo_fd,timebuf,sizeof(timebuf));
        write(log_fd,timebuf,sizeof(timebuf));
        bzero(timebuf,sizeof(timebuf));
        sleep(1);
    }
    
    //4.关闭有名管道
    close(fifo_fd);
    close(log_fd);
    return 0;
    
}
posted @ 2025-08-08 19:31  Lè_Sage  阅读(43)  评论(0)    收藏  举报