Linux无名管道

247 阅读2分钟

无名管道

管道是Linux一种通信机制,是在进程之间建立的一种逻辑上的通道,一端为流入段一端为流出段,一个进程在流入端写入数据,其他进程在流出段按照流入顺序读出数据。

管道的特点:

  • 单工单向通信,管道的数据只能向一个方向传送,发送接收不能同时进行,一旦确定 数据传输方向就不能更改,要实现双向通信需要创建两个管道。 在这里插入图片描述

  • 以字节流形式传送,以字节为单位按照流入顺序传递数据(FIFO)

无名管道与有名管道的区别:

  • 无名管道只能在父子进程间通信,有名管道可以在任意进程间通信
  • 无名管道没有名字标识,有名管道有名称

无名管道的创建

#include <unistd.h>
int pipe(int pipe[2])

若成功,返回0;若出错,返回-1。 pipe[0]用于读管道,pipe[1]用于写管道。

例:利用无名管道实现字符串倒序:父进程通过管道向子进程发送字符串,子进程将其倒序发送给父进程。

// 无名管道
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
char sendbuf[]="taylor swift";
char recbuf[20];
char parrecbuf[20];
void reverse(char *str)//字符串倒序
{
    if(str==NULL)
    return;
    char *p=str;
    char *q=str;
    while(*q)
    ++q;
    q--;
    while(q>p)
    {
        char t=*p;
        *p++=*q;
        *q--=t;
    }
}
int main()
{
    int mypipe[2],fd;
    if(pipe(mypipe)<0)
    {
        perror("pipe failed");
        exit(0);

    }
    if((fd=fork())<0)
    {
        perror("fock failed");
        exit(0);
    }
    if(fd==0){
        read(mypipe[0],recbuf,strlen(sendbuf));
        printf("子进程字符串:%s\n",recbuf);
        reverse(recbuf);
        write(mypipe[1],recbuf,strlen(recbuf));     //向管道写入倒序后字符串
    
    }
    if(fd>0){
        write(mypipe[1],sendbuf,strlen(sendbuf));
        sleep(3);  //  等待子进程
        read(mypipe[0],parrecbuf,strlen(sendbuf));
        printf("父进程字符串:%s\n",parrecbuf);
        wait();
    }

}


在这里插入图片描述

管道的重定向

无名管道可以用来实现进程的输入输出重定向,将某个进程的标准输出与另一个进程的标准输出相连接。实现该功能需要使用dup系统调用

#include<unistd.h>
newfd=dup(oldfd);
newfd=dup2(oldfd,newfd);

dup(oldfd)表示复制文件描述符old,返回值为新的文件描述符newfd。 dup2(oldfd,newfd)相当于" close(newfd);dup(oldfd)",将newfd文件描述符关闭,再将old描述符复制到newfd描述符。

Linux系统将所有设备都当作文件来处理,标准输入的Linux文件描述符是 0,标准输出是 1,标准错误是 2。程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。如果此时去打开一个新的文件,它的文件描述符会是3,依次递增。因此可以利用管道实现标准输入输出的重定向。

例:利用管道实现类似ps -aux|grep init。 在这里插入图片描述 源程序:

#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
void main(){
    int pid,mypipe[2];
    pipe(mypipe);
    pid=fork();
    if(pid<0){
        perror("create process failed\n");
        exit(0);
    }
    if(pid==0){
        close(mypipe[1]);
        dup2(mypipe[0],0);
        close(mypipe[0]);
        sleep(1);
        execlp("grep","grep","init",NULL);
    }
    else{
        close(mypipe[0]);
        dup2(mypipe[1],1);
        close(mypipe[1]);
        execlp("ps","ps","aux",NULL);
    }
}

运行结果: 在这里插入图片描述