Linux关于管道

管道的概念

管道是Unix中最古老的进程间通信的形式。 我们把从一个进程连接到另一个进程的一个数据流称为一个“管道” 我们通常把是把一个进程的输出连接或“管接”(经过管道来连接)到另一个进程的输入。

管道特点

管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。

pipe函数

包含头文件<unistd.h> 功能:创建一无名管道 原型

int pipe(int file_descriptor[2]);

参数 file_descriptor:文件描述符数组,其中file_descriptor[0]表示读端,file_descriptor[1]表示写端 返回值:成功返回0,失败返回错误代码

示例代码:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<string.h>

int main(int argc,char *argv[])
{
    int fd[2];
    printf("f[0]=%d,f[1]=%d\n",fd[0],fd[1]);
    pipe(fd);
    printf("f[0]=%d,f[1]=%d\n",fd[0],fd[1]);

    char buf[1024]={0};
    int fid = fork();
    if(fid > 0)
    {
        read(fd[0],buf,1024);
        printf("read data %s\n",buf);
    }
    else if(fid == 0)
    {
        
        write(fd[1],"helloworld",strlen("helloworld"));

    }
    else
    {
        perror("fork error");
    }
    return 0;
}

打印结果

管道读写规则:如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生 当没有数据可读时,read调用就会阻塞,即进程暂停执行,一直等到有数据来到为止。 如果管道的另一端已经被关闭,也就是没有进程打开这个管道并向它写数据时,read调用就会阻塞

复制文件描述符dup

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>

int main()
{
    int fd = dup(1);

    printf("file fd= %d\n",fd);
    write(fd,"helloworld",strlen("helloworld"));
    return 0;
}

打印结果:

1为输入到终端

shell管道的实现

原理通过把发的fd[1]写复制到shell的1(标准输入),fd[0]复制到shell的2(标准输出)

以下是代码:

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

int main()
{
    int fd[2];
    char buf[1024] ={0};
    pipe(fd);
    int pid = fork();

    if(pid > 0)
    {
        read(fd[0],buf,1024);
        printf(buf);
    }
    else if(pid == 0)
    {
        dup2(fd[1],1);
        close(fd[0]);
        close(fd[1]);
        execlp("ls","ls","-al",NULL);
    }
    else
    {
        
    }
    return 0;
}

实现结果:

popen函数

作用:允许一个程序把另外一个程序当作一个新的进程来启         动,并能对它发送数据或接收数据

FILE* popen(const char *command,                const char *open_mode);

command:待运行程序的名字和相应的参数 open_mode:必须是“r”或“w” 如果操作失败,popen会返回一个空指针

以下代码:

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

int main()
{
    FILE *file = popen("ls -al","r");
    char buf[1024] = {0};
    fread(buf,1,1024,file);
    fclose(file);
    
    FILE *wcfile = popen("wc","w");
    fwrite(buf,1,strlen(buf),wcfile);
    fclose(wcfile);
    return 0;
}

代码结果:

命名管道破裂测试

我们首先要知道命名管道,要读段和写段同时开启,才能向文件读写数据。

贴上代码来理解命名管道的规则

首先是读端:

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

int main(int argc,char *argv[])
{
    printf("open before\n");
    int fd = open("/home/gao/tmp/fifo",O_RDONLY);
    printf("open after\n");

    //休眠5秒,读端退出
    sleep(5);
    return 0;
}

接下来是写端:

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

void handle(int signo)
{
    printf("cat signale = %d\n",signo);
}

int main(int argc,char *argv[])
{
    signal(SIGPIPE,handle);
    printf("open before\n");
    int fd = open("/home/gao/tmp/fifo",O_WRONLY);
    printf("open after\n");
    //命名管道规则,如果写入读断被中断,写入会返回-1,并且管道会破裂,产生信号(SIGPIPE)
    while(1)
    {
     int wrsize = write(fd,"helloworld",strlen("helloworld"));
     printf("size data:%d\n",wrsize);
     sleep(1);
    }   
}

执行写端:

它在等待另一端的开启,才能向里面写入数据

此时我们开启读端:

马上可以看到写段可以写数据

而执行5秒后,我们可以看到写的时候返回-1,并且获取到管道破裂的信息(SIGPIPE)

所以这里就是我们所注意的点,当我们写客户端和服务器进行管道传输的时候,如果客户端一旦退出来,就会使管道破裂,所以我们必须通过捕捉信号,来避免这种事情发生。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值