linux C--管道

链接: linux C学习目录

linux C 管道

  • 基本概念
  • 管道特征
  • 编写模型
    • 有名管道模型
      • 示例demo
        • write.c
        • read.c
      • 结果记录
      • 笔记1
    • 无名管道

基本概念

进程间存在天然的壁垒,进程间通信(Interperocess Communication,IPC)是指二个或者多个进程之间进行数据交换的过程

管道特征

管道是进程间通讯的一种常用方法。管道分为有名管道fifo无名管道pipe

  • 管道创建后是单向的,一端是写,一端是读(如果需要想双向,没办法创建二根管道)
  • 管道有大小,linux内核对每个管道的大小限制在4096字节
  • 无名管道一般用在父子线程间通讯
  • 有名管道一般用在进程和不同线程之间通讯
  • 管道是阻塞的,读取管道过程中一直处于阻塞的状态
  • 管道在被读取前,只能写入一次,多次写入是无效的

编写模型

有名管道模型

步骤 进程A 进程B 步骤
1.创建管道 mkfifo
2.打开管道 open open 1.打开管道
3.读写管道 write/read write/read 2.读写管道
4.关闭管道 close close 3.关闭管道
5.删除管道 unlink

示例demo

注意:有名管道需要依靠文件来传递,我们在/tmp目录下去建文件,因为tmp目录是临时目录,开机就清除了

write.c
#include 
#include 
#include 
#include 
#include 

#define FIFO_FILE "/tmp/fifo"

int main(void){
    printf("创建管道...\n");
    if(mkfifo(FIFO_FILE,0666) == -1){
        perror("mkfifo");
        return -1;    
    }
    
    printf("打开管道...\n");
    int fd = open(FIFO_FILE,O_WRONLY);
    if(fd == -1){
        perror("open");
        return -1;
    }
    
    printf("发送数据...\n");
    for(;;){
        printf(">");
        char buf[1024];
        gets(buf);
        if(!strcmp(buf,"!"))
            break;
        if(write(fd,buf,(strlen(buf)+1)))  * sizeof(buf[0]) == -1){
            perror("write");
            return -1;        
        }                     
    }
    
    printf("关闭管道...\n");
    if(close(fd) == -1){
        perror("close");
        return -1;    
    }
    
    printf("删除管道...\n");
    if(unlink(FIFO_FILE) == -1){
        perror("unlink");
        return -1;    
    }
    
    printf("大功告成!\n");
    return 0;
}
read.c
#include 
#include 
#include 

#define FIFO_FILE "/tmp/fifo"

int main(void){
    printf("打开管道...\n");
    int fd = open (FIFO_FILE,O_RDONLY);
    if(fd == -1){
        perror("open");
        return -1;
    }
    
    printf("接收数据...\n");
    for(;;){
        char buf[1024];
        size_t rb = read(fd,buf,sizeof(buf));
        if(rb == -1){
            perror("read");
            return -1;
        }    
        
        if(!rb)
            break;
        printf("< %s\n",buf);
    }
    
    printf("关闭管道...\n");
    if(close(fd) == -1){
        perror("close");
        return -1;
    }
    
    printf("大功告成!\n");
    return 0;

结果记录

我们先编译一下
linux C--管道_第1张图片
生成writeread二个可执行文件
linux C--管道_第2张图片

我们测试一下管道linux C--管道_第3张图片
最后记得删除管道,不然再创建的时候会有一些莫名错误!

笔记1

我们再尝试一下,打开管道的命令在linux中也是一个阻塞的操作我们修改一下write.c的代码

 //服务信息
    while(1)
    {
        char buffer[128]={0};

        //打开管道文件
        printf("打开管道中...\r\n");
        fd=open(FIFO,O_RDONLY);
        if(fd<0) {
            printf("打开管道:失败!\r\n");
            return(-2);
        }
        else {
            printf("打开管道:成功!\r\n");
        }

        //输出标识词
        printf("Recv Data:");
        //读取管道数据
        ssize_t s=read(fd,buffer,sizeof(buffer)-1);


        if(s>0) {
            buffer[s]=0;
            printf("%s\r\n",buffer);
        }

        if(close(fd) == -1){
            printf("close false!\r\n");
            return -1;
        }
    }

记录一下运行的结果
linux C--管道_第4张图片
发现open管道其实是阻塞了线程,这些阻塞的地方我们称为焦点,理解这些焦点对我们编写代码很重要。
我们再看一下管道的文件,在tmp临时文件夹中我们创建的管道文件。
linux C--管道_第5张图片

无名管道

这个比较简单直接上代码

#include 
#include 
#include 
#include 

int main(void){
    printf("父进程:创建管道...\n");
    int pipefd[2];
    
    if(pipe(pipefd) == -1){
        perror("pipe");
        return -1;    
    }
    
    printf("父进程:创建进程...\n");
    pid_t pid = fork();
    if(pid == -1){
        perror("fork");
        return -2;    
    }
    
    /* fork之后就多了一个子进程,父进程和子进程在宏观
    上是并发的关系,这样就理解为2个mian函数一起运行了
    之后我们用if判断语句来做分支处理,这样实现pipe的
    通讯*/
    
    
    if(pid == 0){
        printf("子进程:关闭写端...\n");
        close(pipefd[1]);
        printf("子进程:接收数据...\n");
        for(;;){
            char buf[1024];
            ssize_t rb = read(pipefd[0],buf,sizeof(buf));
            if(rb == -1){
                perror("read");
                return -1;            
            }
            else if(rb == 0){
                //注意:如果读到的返回结果是0,说明pipe被关闭了,这个时候结束
                break;            
            } 
            
            puts(buf);  //数据打印出来            
        }
        printf("子进程:关闭读端...\n");
        close(pipefd[0]);
        printf("子进程:大功告成!\n");
    }
    
    printf("父进程:关闭读端...\n");
    close(pipefd[0]);
    printf("父进程:发送数据...\n");
    for(;;){
        char buf[1024];
        if(!strcmp(buf,"!")) {
            break;        
        }   
        
        if(write(pipefd[1],buf,strlen(buf)+1) == -1){
            perror("write");
            return -1;        
        }
    }
    printf("父进程:关闭写端...\n");
    close(pipefd[1]);
    if(wait(0) == -1){
        perror("wait");
        return -1;    
    }
    
    printf("父进程:大功告成!\n");
    return 0;
}

你可能感兴趣的:(linux,C,linux,c语言)