一 管道的概念:

管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:

1. 其本质是一个伪文件(实为内核缓冲区)

2. 由两个文件描述符引用,一个表示读端,一个表示写端。

3. 规定数据从管道的写端流入管道,从读端流出。

管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。

管道  分为 标准流管道,无名管道(PIPE),命名管道(FIFO)

管道的局限性:

① 数据自己读不能自己写。

② 数据一旦被读走,便不在管道中存在,不可反复读取。

③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。

其中 无名管道 ’标准管道 只能在有公共祖先的进程间使用管道。

二 无名管道建立流程

 

 demo 两个子进程 写父进程读

#include <stdio.h>

#include <unistd.h>

#include <sys/wait.h>

#include <string.h>

#include <stdlib.h>

int main(void)
{

    pid_t pid;

    int fd[2], i, n;

    char buf[1024];

    int ret = pipe(fd);

    if (ret == -1)
    {

        perror("pipe error");

        exit(1);
    }

    for (i = 0; i < 2; i++)
    {

        if ((pid = fork()) == 0)
        {
            if (i == 0)
            {

                close(fd[0]);

                write(fd[1], "1.hello\n", strlen("1.hello\n"));
            }
            else if (i == 1)
            {

                close(fd[0]);

                write(fd[1], "2.world\n", strlen("2.world\n"));
            }
            break;
        }

        else if (pid == -1)
        {

            perror("pipe error");

            exit(1);
        }
    }

    if (pid > 0)
    {

        close(fd[1]); //父进程关闭写端,留读端读取数据

        // sleep(1);

        n = read(fd[0], buf, 1024); //从管道中读数据

        write(STDOUT_FILENO, buf, n);
        

        for (i = 0; i < 2; i++) //两个儿子wait两次

            wait(NULL);
    }

    return 0;
}

结果 

三 标准管道

 demo

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#define BUFSIZE 1024
int main()
{
    FILE *fp;
    char *cmd = "printenv";
    char buf[BUFSIZE];
    buf[BUFSIZE-1] = '\0';
    if((fp=popen(cmd,"r"))==NULL)
        perror("popen");
    
    while((fgets(buf,BUFSIZE,fp))!=NULL)
        printf("%s",buf);
    
    pclose(fp);
    exit(0);
}

 

四 FIFO


上述管道虽然实现了进程间通信,但是它具有一定的局限性:首先,这个管道只能是具有血缘关系的进程之间通信;第二,它只能实现一个进程写另一个进程读,而如果需要两者同时进行时,就得重新打开一个管道。 
为了使任意两个进程之间能够通信,就提出了命名管道(named pipe 或 FIFO)

不支持seek 先进先出

原型

fifo_read.c

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
 
int main()
{
	int fd;
	int len;
	char buf[1024];
 
	if(mkfifo("fifo1", 0666) < 0 && errno!=EEXIST) // 创建FIFO管道
		perror("Create FIFO Failed");
 
	if((fd = open("fifo1", O_RDONLY)) < 0)  // 以读打开FIFO
	{
		perror("Open FIFO Failed");
		exit(1);
	}
	
	while((len = read(fd, buf, 1024)) > 0) // 读取FIFO管道
		printf("Read message: %s", buf);
 
	close(fd);  // 关闭FIFO文件
	return 0;
}

 

 fifo_read.c

#include<stdio.h>
#include<stdlib.h>   // exit
#include<fcntl.h>    // O_WRONLY
#include<sys/stat.h>
#include<time.h>     // time
 
int main()
{
	int fd;
	int n, i;
	char buf[1024];
	time_t tp;
 
	printf("I am %d process.\n", getpid()); // 说明进程ID
	
	if((fd = open("fifo1", O_WRONLY)) < 0) // 以写打开一个FIFO 
	{
		perror("Open FIFO Failed");
		exit(1);
	}
 
	for(i=0; i<10; ++i)
	{
		time(&tp);  // 取系统当前时间
		n=sprintf(buf,"Process %d's time is %s",getpid(),ctime(&tp));
		printf("Send message: %s", buf); // 打印
		if(write(fd, buf, n+1) < 0)  // 写入到FIFO中
		{
			perror("Write FIFO Failed");
			close(fd);
			exit(1);
		}
		sleep(1);  // 休眠1秒
	}
 
	close(fd);  // 关闭FIFO文件
	return 0;
}

 

 

Logo

更多推荐