linux C--管道

文章详细介绍了Linux系统中C语言实现的管道通信机制,包括有名管道(FIFO)和无名管道的创建、读写操作以及示例代码。通过管道,进程间可以实现单向数据传递,有名管道借助文件系统实现跨进程通信,而无名管道主要用于父子进程间的通信。文章还提到了管道的阻塞特性及其在代码中的应用。
摘要由CSDN通过智能技术生成

链接: linux C学习目录

基本概念

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

管道特征

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

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

编写模型

有名管道模型

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

示例demo

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

write.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#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 <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#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;

结果记录

我们先编译一下
在这里插入图片描述
生成writeread二个可执行文件
在这里插入图片描述

我们测试一下管道在这里插入图片描述
最后记得删除管道,不然再创建的时候会有一些莫名错误!

笔记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;
        }
    }

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

无名管道

这个比较简单直接上代码

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值