有名管道

管道没有名字,它的通信只限定于亲缘关系间的通信,有名管道实现了无亲缘关系间的通信,原理是fifo提供了一个路径名与之关联,让fifo的文件存于系统中,只要知道该文件路径,就可以进行访问。fifo指代(fist in, fist out),即按照先进先出的工作。

  • fifo 创建
#include <sys/types.h>

#include <sys/stat.h>



int mkfifo(const char * pathname, mode_t mode);

参数:
pathname 为路径名,创建管道的名字
mode 为创建fifo的权限

 

例1,该程序让子进程执行了ls-l命令,并将执行结果写入有名管道,父进程从该管道中读出执行结果,输出到屏幕,最后删除该有名管道的文件

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <fcntl.h>

#include <string.h>

#include <sys/stat.h>

#include <errno.h>

#include <unistd.h>



#define FIFO2 "/tmp/fifo.2"

int main(int argc, int ** argv)

{

    int readfd,writefd;

    pid_t pid;

    char buf[1001];

    //建立有名管道    S_IFIFO|0666指名创建有名管道且存取权限为0666,即创建者/其同组用户/其他用户均可读可写

    if(mkfifo(FIFO2, S_IFIFO|0666)< 0)

    {

        printf("mkfifo2 error");

        exit(1);

    }

    if((pid = fork()) == 0) //创建进程 子进程写

    {

        writefd = open(FIFO2, O_WRONLY);  //打开管道以写方式

        dup2(1, writefd); //定向输出的东西到管道输入

        execlp("ls", "ls", "-l", NULL);//子进程执行ls -l 命令, 即执行结果到有名管道中

    }



    readfd = open(FIFO2, O_RDONLY);//打开管道以读方式

    while(read(readfd, buf, 1000) != 0)

    {

        printf("%s", buf);    //读出管道东西到屏幕

    }

    waitpid(pid, NULL, 0);//等待子进程结束

    close(readfd);

    close(writefd);

    unlink(FIFO2);//删除FIFO2文件

    exit(0);

}



注:有名管道需要用open函数打开以后使用,如果以读方式打开,会阻塞到有写方打开管道,同样以写方式打开会阻塞到以读方式打开,若同时打开读写,则不会阻塞,在该程序中一定会先执行子进程,因为父进程读管道时,管道中没有数据,也会阻塞read到有write写入到管道中

例2,上一个程序是亲缘关系间的通信,该程序是无亲缘关系间的通信,该程序只写了一个服务器端,写了shell与其通信,题目是shell脚本中的客户进程请求服务器返回指定一个文件的内容,请求格式为进程id、空格、路径名、换行符构成,该程序类型为多个客户,一个服务器

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <fcntl.h>

#include <string.h>

#include <sys/stat.h>

#include <errno.h>

#include <unistd.h>



#define FIFO  "/tmp/fifo.serv"  

#define MAXLINE 80



int main(int argc, int ** argv)

{

    int readfd,writefd,fd;

    char *ptr, buff[MAXLINE], fifoname[MAXLINE];

    pid_t pid;

    ssize_t n;



    if(mkfifo(FIFO,S_IFIFO|0666 )< 0)//创建管道

    {

        printf("mkfifo error");

        exit(1);

    }



    readfd = open(FIFO, O_RDONLY); //以不阻塞的方式打开服务器管道,

    writefd = open(FIFO, O_WRONLY);

                                                                                     

      while ((n = read(readfd, buff, MAXLINE)) > 0)  //读服务器管道内容,读出客户请求

    {

        if(buff[n-1] == '\n') //去掉换行符

        {

            n--;    

        }

        buff[n] = 0;

        if((ptr = strchr(buff, ' ')) == NULL) //定位空格

        {

            printf("pathname :%s", buff);

            continue;

        }

        *ptr++ = 0;

        printf("ptr = %s\n", ptr); //打印客户要求输出的文件名

        pid = atol(buff);     //取出进程id

        snprintf(fifoname ,sizeof(fifoname), "/tmp/fifo.%ld", (long)pid);  //组织客户管道名称

        printf("fifoname = %s\n", fifoname);        //输出客户管道名称

        if((writefd =  open (fifoname, O_WRONLY, 0)) < 0)  //打开客户管道,以写方式打开

        {

            printf("can't open %s\n", fifoname);

            continue;

        }

        if((fd = open(ptr, O_RDONLY)) < 0) //打开客户请求的文件

        {

            snprintf(buff+n, sizeof(buff) - n, ":can't open, %s\n", strerror(errno));

            n = strlen(ptr);

            write(writefd, ptr, n);

            close(writefd);

        }

        else

        {

            while((n = read(fd, buff, MAXLINE)) > 0)    //将客户请求的文件写入到客户管道中

                write(writefd, buff, n);

            close(fd);

            close(writefd);

        }

    }



    return 0;

}

shell交互内容,我本目录下写了一个test.c文件,
pid=$$                        获取本进程id
mkfifo /tmp/fifo.$pid          创建客户管道
echo "$pid test.c" > /tmp/fifo.serv  将请求写入服务器管道
cat < /tmp/fifo.$pid   输出服务器返回给客户管道内容
rm /tmp/fifo.$pid  删除客户管道

 

该程序中因为while循环中的read会阻塞到有客户进程往服务器管道中写如数据的时候,即实现了只要有客户进程访问数据服务器就会给出应答,否则一直等待。

 

 

你可能感兴趣的:(管道)