第04章 管道和FIFO

1.管道的概念:

  • 管道本质还是以文件作为通信媒介,叫管道文件
  • 分类:
    • 无名管道(pipe):没有名字,由内核创建,具有亲缘关系的进程才能使用
    • 有名管道(fifo):有名字,由程序员创建,任意两个进程都能使用它进行通信

2.无名管道(PIPE)的创建:

#include <unistd.h>
int pipe(int pipefd[2]);
  • 功能:用来在内核中创建无名管道
  • 参数:整型数组,用来存放管道的读/写的文件描述符

    • pipefd[0]:存放读端的文件描述符
    • pipefd[1]:存放写端的文件描述符
    • 返回值:成功返回0,失败返回-1,errno被设置
  • 无名管道的读写:

    • 1.用pipe创建出来的管道两端处于同一进程之中,通常的做法,先创建一个管道,再fork一个子进程,子进程会复制父进程的文件描述符,为了实现父子进程间的正常通信,一般需要把无关的读/写端关掉。
    • 2.用pipe创建的管道默认情况下是阻塞的
      去读一个管道时,如果管道中没有数据,则阻塞到有数据读为止
      去往管道中写数据时,如果管道写满,则写阻塞直到有进程把数据读走
    • 3.数据一旦被读走,就没有了!
    • 练习:
      父进程从标准输入获取文件名,通过管道发送给子进程
      子进程收到文件名,打开文件,把文件的数据发送给父进程
      父进程收到子进程返回的数据,打印到标准输出。

3.有名管道(FIFO):

  • 为了克服无名管道的缺点,提出了有名管道
  • 有名管道可用于任意进程之间的通信,它提供了一个路径名与之关联,以FIFO的形式存在于文件系统中。
  • 创建之后,进程就可以像普通文件一样去操作,但不支持lseek
  • 创建:
    • 指令:
      • mkfifo 名字 //注意不要在共享目录下创建,会失败
    • 接口:
    #include <sys/types.h>
    #include <sys/stat.h>
    int mkfifo(const char *pathname, mode_t mode);
  • 功能:用来在内核中创建有名管道
  • 第一个参数:要创建的有名管道的文件名(不要在共享目录下创建),建议带上路径
  • 第二个参数:权限,与open的第三个参数同。
  • 返回值:成功返回0,失败返回-1,errno被设置

  • 有名管道使用说明:

    • 1.打开有管道时,默认是阻塞的,即如果往管道中写数据,必须要有进程来读,写数据的进程才会返回;如果从管道中读数据,必须要有进程往管道中写数据,读数据的进程才会返回。
    • 2.如果以非阻塞的方式打开有名管道,如果往管道中写数据,而没有进程去读,会立即出错返回;如果从管道中读数据,而没有进程往管道中写数据,会立即返回(不是出错,是没有读到任何数据)
  • 下面是一个管道的例子,程序原运行后再输入一个文件名,程序打印文件内容:

#include <stdio.h>
#include <unistd.h>
#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <fcntl.h>              /* Obtain O_* constant definitions */
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <error.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>

void client(int,int),server(int,int);
#define MAXLINE     4096    /* max text line length */
#define FIFO_NAME "/tmp/mplayer.fifo"
int main(int argc,char *argv[]){

    int pipe1[2],pipe2[2],r,fd;
    pid_t childpid;
    int check_up=0;
    check_up=pipe(pipe1);
    assert(check_up>=0);
    check_up=pipe(pipe2);
    assert(check_up>=0);
    r = mkfifo(FIFO_NAME, 0755);
    if( -1 == r){
        assert(errno == EEXIST);
    }
    fd = open(FIFO_NAME, O_RDWR);
    assert(fd!=-1);

    struct stat buf;
    fstat(pipe1[0],&buf);
    if((check_up=S_ISFIFO(buf.st_mode))){//这里的返回值是1
        printf("check_up=%d,pipe1[0] is a fifo file\n",check_up);
    }else{
        printf("it is ...\n");
    }
    fstat(fd,&buf);
    if((check_up=S_ISFIFO(buf.st_mode))){//这里的返回值为什么也是1,有大佬能解释一下吗
                                    //如果都一样怎么区分管道和FIFO
        printf("check_up=%d,fd is a fifo file\n",check_up);
    }else{
        printf("it is ...\n");
    }

    childpid=fork();
    assert(childpid>=0);
    if(childpid==0){
        close(pipe1[1]);//用1读
        close(pipe2[0]);//用2写

        server(pipe1[0],pipe2[1]);
        exit(0);
    }
    close(pipe1[0]);//用1写
    close(pipe2[1]);//用2读
    client(pipe2[0],pipe1[1]);
    exit(0);
}
void client(int readfd, int writefd)
{
    size_t  len;
    ssize_t n;
    char    buff[MAXLINE];

        /* 4read pathname */
    fgets(buff, MAXLINE, stdin);
    len = strlen(buff);     /* fgets() guarantees null byte at end */
    if (buff[len-1] == '\n')
        len--;              /* delete newline from fgets() */

        /* 4write pathname to IPC channel */
    write(writefd, buff, len);

        /* 4read from IPC, write to standard output */
    while ( (n = read(readfd, buff, MAXLINE)) > 0)
        write(STDOUT_FILENO, buff, n);
}
void server(int readfd, int writefd)
{
    int     fd;
    ssize_t n;
    char    buff[MAXLINE+1];

        /* 4read pathname from IPC channel */
    if ( (n = read(readfd, buff, MAXLINE)) == 0){
        printf("end-of-file while reading pathname");
        exit(0);
    }
    buff[n] = '\0';     /* null terminate pathname */

    if ( (fd = open(buff, O_RDONLY)) < 0) {
            /* 4error: must tell client */
        snprintf(buff + n, sizeof(buff) - n, ": can't open, %s\n",
                 strerror(errno));
        n = strlen(buff);
        write(writefd, buff, n);

    } else {
            /* 4open succeeded: copy file to IPC channel */
        while ( (n = read(fd, buff, MAXLINE)) > 0)
            write(writefd, buff, n);
        close(fd);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值