进程通信——有名管道

       有名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和之前所讲的没有名字的管道(匿名管道)类似。

       (在磁盘上存在这样的文件;伪文件,该文件在磁盘大小永远为0;在内核中有一个对应的缓冲区;半双工的通信方式;没有血缘关系的进程间通信)
         “Linux系统一切皆文件” ,所以对有名管道的使用也就变得与文件操作(可以使用I/O函数进行操作open/close、read/write)非常的统一,也使它的使用非常方便,同时我们也可以像平常的文件名一样在命令中使用。

创建有名管道
我们可以使用两下函数之一来创建一个有名管道,原型如下:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *filename, mode_t mode);
int mknod(const char *filename, mode_t mode | S_IFIFO, (dev_t)0);
这两个函数都能创建一个FIFO文件,注意是创建一个真实存在于文件系统中的文件,filename指定了文件名,而mode则指定了文件的读写权限。

mknod是比较老的函数,而使用mkfifo函数更加简单和规范,所以建议在可能的情况下,尽量使用mkfifo而不是mknod。

访问有名管道

打开FIFO文件
       与打开其他文件一样,FIFO文件也可以使用open调用来打开。注意,mkfifo函数只是创建一个FIFO文件,要使用有名管道还是将其打开。

      注意:a.就是程序不能以O_RDWR模式打开FIFO文件进行读写操作,而其行为也未明确定义,因为如一个管道以读/写方式打开,进程就会读回自己的输出,同时我们通常使用FIFO只是为了单向的数据传递。b.就是传递给open调用的是FIFO的路径名,而不是正常的文件。

       打开FIFO文件通常有四种方式,
open(const char *path, O_RDONLY);//1
open(const char *path, O_RDONLY | O_NONBLOCK);//2
open(const char *path, O_WRONLY);//3
open(const char *path, O_WRONLY | O_NONBLOCK);//4
        在open函数的调用的第二个参数中,选项O_NONBLOCK表示非阻塞,加上这个选项后,表示open调用是非阻塞的,如果没有这个选项,则表示open调用是阻塞的。

       open调用的阻塞:对于以只读方式(O_RDONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_RDONLY),除非有一个进程以写方式打开同一个FIFO,否则它不会返回;如果open调用是非阻塞的的(即第二个参数为O_RDONLY | O_NONBLOCK),则即使没有其他进程以写方式打开同一个FIFO文件,open调用将成功并立即返回。

      对于以只写方式(O_WRONLY)打开的FIFO文件,如果open调用是阻塞的(即第二个参数为O_WRONLY),open调用将被阻塞,直到有一个进程以只读方式打开同一个FIFO文件为止;如果open调用是非阻塞的(即第二个参数为O_WRONLY | O_NONBLOCK),open总会立即返回,但如果没有其他进程以只读方式打开同一个FIFO文件,open调用将返回-1,并且FIFO也不会被打开。
有名管道进程间的通信和文件操作相同。将管道看做是文件即可。

1、首先新建一个管道:mkfifo myfifo

管道要操作要有两个文件a.c和b.c,管道中无数据,即a未输入,则b会自动阻塞,a.c写端关闭,b.c读端返回0,a.c写,b.c读,没有写,就没有读。
2、向管道写入数据

a.c

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
 
int main()
{
    int fdw = open("./myfifo",O_WRONLY);
    if(fdw == -1)
    {
        printf("open error");
        exit(0);
    }
    while(1)
    {
       char buff[128]={0};
       fgets(buff,128,stdin);
       write(fdw,buff,strlen(buff);
    }
    close(fdw);
    exit(0);
}

3、从管道中读出数据

b.c

# include <stdio.h>
# include <stdlib.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <unistd.h>
# include <string.h>
# include <fcntl.h>
 
int main()
{
    int fdr = open("./myfifo",O_RDONLY);
    if(fdr == -1)
    {
        printf("open error");
        exit(0);
    }
    char buff[128] = {0};
    while(1)
    {
         read(fdr,buff,127);
         printf("read:%s\n",buff);
         if(read(fdr,buff,127)==0)
         {break;}       
         close(fdr);
   }
}

总结:a.有名管道的属性信息是存在磁盘上的,比如:属主、创建时间、权限、名字等

            b.写入管道的数据在内存中

            c.要打开有名管道,需要两个进程,一个读,一个写

            d.写端关闭,读端(read)返回,返回值为0

            e.读端关闭(对方一旦关闭读,就不能写了)收到读端触发的SIGPIPE信号,默认终止程序。

猜你喜欢

转载自blog.csdn.net/Aspiration_1314/article/details/83066515