Linux管道通信

无名管道和有名管道

先说一下有名管道和无名管道用的函数:

无名管道使用的是 pipe()

有名管道使用的是fifo()

无名管道主要用于有血缘关系的两个进程间通信,是内核使用环形队列机制实现,借助内核缓冲区实现的。有名管道主要用于两个不相干的进程间通信,我认为之所以叫有名管道是因为他们借助mkfifo()函数创建的伪文件利用内核缓冲区进行通信,因为创建文件可以指定文件名所以操作和使用文件几乎一样。

首先关于无名管道 pipe()函数 需要指定两个文件描述符,通过pipe()函数创建一个管道使其一端读文件一端写文件。而fifo()函数是一个进程写数据,一个进程读数据,两个进程不能结束

1、无名管道

无名管道是作为一个半双工的通信模式,具有固定的读写端。并且他只能在具有亲缘关

系的进程之间通信,实现依赖父子进程文件共享,可以把它看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。

函数原型:int pipe(int fd[2]);该函数由参数fd返回两个文件操作符,fd[0]作为读端,fd[1]作为写端(注意:由于是半双工因此不能同时读写,因此在需要读的进程中要close(fd[1]),而在写进程中close(fd[0]))。单个进程中的管道几乎没有任何用处,通常,调用pipe的进程接着调用fork(创建进程)。

注:

(1)当读一个写端已被关闭的管道是,在所有数据都被读取后,read返回0,以指示达到文件结束处。管道的写端彻底关闭(父子进程的写端都得关闭,否则会有进程处于未关闭状态,还在等待写),读端返回一个0,父子进程都得关闭。

(2)如果写一个读端已被关闭的管道,则产生信号SIGPIPE。如果忽略该信号或者捕捉该信号并从处理程序返回,则write返回-1,errno设置为EPIPE。

(3)示例代码见附录1。
Linux管道通信_第1张图片
2、有名管道

有名管道也叫命名管道,在文件系统目录中存在一个管道文件。管道文件仅仅是文件系统中的标示,并不在磁盘上占据空间。在使用时,在内存上开辟空间,作为两个进程数据交互的通道。

管道文件的创建:

  1. 在shell中使用mkfifo 命令

mkfifo filename

  1. mkfifo 函数 (在代码中使用其创建管道文件)

函数原型:int mkfifo(const char *filename,mode_t mode);

使用方式:

  1. 使用open函数打开管道文件

如果一个进程以只读(只写)打开,那么这个进程会被阻塞到open,直到另一个进程以只写(只读)或者读写打开。

  1. 使用read函数读取内容

read读取普通文件,read不会阻塞。而read读取管道文件,read会阻塞运行,直到管道中有数据或者所有的写端关闭。

  1. 使用write函数发送内容,使用close函数关闭打开的文件。

总结:

(1)两个进程运行时,写端彻底关闭,则读端read返回0,也会关闭。

(2)如果管道的读端关闭,继续写入数据会发生异常,写端收到未捕获的信号SIGPIPE会关闭写端。当然也可以修改默认的信号响应方式,比如增加信号处理函数。

(3)写端写入数据以后,读端不从里面读取内容:数据保持在管道中存在一段时间。管道文件的大小是0。

(4)管道通讯发送的数据若没有指定进程接收,任何一个进程只要打开的是同一个管道文件,都有可能读到数据。

(5)read读取管道中的数据,只要读过的数据就会被清空 。

附录一:
#include 
#include 
#include 
#include 

int main(void)
{
    int fd[2];
    int ret = pipe(fd);
    if (ret == -1)
    {
        perror("pipe error!");
        exit(-1);
    }
    pid_t pid = fork();
    if (pid == -1)
    {
        perror("fork error!");
        exit(-1);
    }
    else if (pid == 0)//子进程读数据
    {
        close(fd[1]);
        char buf[1024];
        ret = read(fd[0], buf, sizeof(buf));
        if (ret == 0) printf("------\n");
        write(STDOUT_FILENO, buf, ret);
    }
    else
    {
        close(fd[0]);// 父进程写数据
        char* str = "Hello pipe\n";
       write(fd[1], str, strlen(str));
        sleep(2);
    }
}

你可能感兴趣的:(Linux)