linux 有名管道

有名管道:

  匿名管道,由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道(FIFO),也叫命名管道、FIFO文件

  有名管道(FIFO)不同于匿名管道之处在于它提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,并且其打开方式与打开一个普通文件是一样的,这样即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,通过 FIFO 不相关的进程也能够交换数据

  一旦打开了 FIFO ,就能在它上面使用与操作匿名管道和其他文件的系统调用一样的  I/O  系统调用(如   read()  write()   和  close()  。与管道一样, FIFO 也有一个写入端和读取端,并且从管道中读取数据的顺序与写入的顺序是一样的。  FIFO 的名称也由此而来:  先入先出     

  有名管道(FIFO)和匿名管道(pipe)有一些特点是相同的,不一样的地方在于:

    1.FIFO 在文件系统中作为一个特殊文件存在,但 FIFO  中的内容却存放在内存中

    2.当使用 FIFO  的进程退出后, FIFO 文件将继续保存在文件系统中以便以后使用

    3.FIFO 有名字,不相关的进程可以通过打开有名管道进行通信。 

  通过命令创建有名管道

    mkfifo  名字

  通过函数创建有名管道

    #include <sys/types.h>

    #include <sys/stat.h>

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

  一旦使用  mkfifo  创建了一个 FIFO  ,就可以使用 open  打开它, 常见的文件  I/O  函数都可以用于 fifo   如: close、read、write、unlink  等。

  FIFO 严格遵循先进先出 (First in First out),对管道及 FIFO 的读总是从开始处返回数据,对他们的写则把数据添加到末尾。他们不支持诸如  lseek()  等文件定位操作。

       prw:p表示管道  

mkfifo() 

复制代码
 1 /*
 2     man 3 fifo
 3     创建fifo文件
 4     1.通过命令: mkfifo 名字
 5     2.通过函数: int mkfifo(const char* pathname, mode_t mode);
 6 
 7     #include <sys/types.h>
 8     #include <sys/stat.h>
 9     int mkfifo(const char* pathname, mode_t mode);
10         参数:
11             - pathname:管道名称的路径(绝对路径/相对路径(当前))
12             - mode: 文件的权限 和 open的 mode是一样的
13                     是一个八进制的数
14         返回值:
15             成功:返回  0
16             失败:返回 -1 并设置错误号
17 */
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <stdlib.h>
22 
23 int main()
24 {
25     int ret = mkfifo("fifo1",0664);
26     if(ret == -1)
27     {
28         perror("mkfifo");
29         exit(0);
30     }
31     return 0;
32 }
复制代码

案例:    write.c     read.c  

写入:

复制代码
 1 //向管道中写数据
 2 /*
 3     有名管道的注意事项:
 4         1.一个为只读而打开一个管道的进程会阻塞,直到另外一个进程为只写打开管道
 5         2.一个为只写而打开一个管道的进程会阻塞,直到另外一个进程为只读打开管道
 6     读管道:
 7         管道中有数据,read返回实际督导的字节数
 8         管道中无数据:
 9             管道写端被全部关闭, read返回0  (相当于读到文件末尾)
10             写端没有全部被关闭, read阻塞等待
11     写管道:
12         管道读端被全部关闭,进程异常终止(收到一个 SIGPIPE信号)
13         管道读端没有全部关闭:
14             管道已经满了,write会阻塞
15             管道没有满,write将数据写入,并返回实际写入的字节数
16 */
17 #include <stdio.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <string.h>
24 int main()
25 {
26     //1.判断文件是否存在
27     int ret = access("test",F_OK);//判断文件是否存在
28     if(ret == -1)
29     {
30         //2.创建管道文件
31         printf("管道不存在,创建管道\n");
32         ret = mkfifo("test",0664);
33         if(ret == -1)
34         {
35             perror("mkfifo");
36             exit(0);
37         }
38     }
39     //3.打开管道  以  只写  的方式打开管道(只读错误 可读写容易出错) 
40     int fd = open("test",O_WRONLY);
41     if(fd == -1)
42     {
43         perror("open");
44         exit(0);
45     }
46     //写数据
47     for(int i = 0; i< 100;i++)
48     {
49         char buf[1024];
50         sprintf(buf,"hello,%d\n",i);
51         printf("write data : %s\n",buf);
52         write(fd,buf,strlen(buf));
53         sleep(1);
54     }
55     close(fd);
56     return 0; 
57 }
复制代码

读取数据: 

复制代码
 1 //从管道中读数据
 2 #include <stdio.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <stdlib.h>
 6 #include <unistd.h>
 7 #include <fcntl.h>
 8 #include <string.h>
 9 int main()
10 {
11     //1.打开管道文件
12     int fd = open("test",O_RDONLY);//只读
13     if(fd == -1)
14     {
15         perror("open");
16         exit(0);
17     }
18     //读取数据
19     while(1)
20     {
21         char buf[1024] = {0};
22         int len = read(fd,buf,sizeof(buf));
23         if(len == 0)
24         {
25             printf("写端断开连接了...\n");
26             break;
27         }
28         printf("recv buf: %s\n",buf);
29     }
30     close(fd);
31     return 0;
32 }
复制代码

    

 运行时,需要两个终端分别运行 读取可执行程序和写入可执行程序,有一端关闭 则管道阻塞。  

posted on   廿陆  阅读(101)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示