python 命名管道_管道和FIFO(命名管道 named pipe)的比较

管道和FIFO(命名管道 named pipe)的比较:

主要区别在于被创建和访问的方式上。

管道(pipe)

管道在Unix及Linux进程间通信是最基础的,很容易理解。管道就像一个自来水管,一端注入水,一端放出水,水只能在一个方向上流动,而不能双向流动。管道是典型的单向通信,即计算机网络中所说的“半双工”。管道又名匿名管道,所以只能用在具有公共祖先的进程之间使用,通常使用在父子进程之间通信。通常是父进程创建一个管道,然后fork一个子进程,此后父子进程共享这个管道进行通信。

管道由pipe函数创建,函数原型如下:

#include

int  pipe(int fd[2]); 成功返回0,否则返回-1;参数fd返回两个文件描述符,fd[0]为读,fd[1]为写,fd[1]的输入是fd[0]的输出。即fd[0]对应读端,fd[1]对应写端。

举例说明一下管道的用法:模拟client-server通信过程,父进程模拟client,子进程模拟server。server向client发送一个字符串,client接收到输出到屏幕。

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7

8 int main()

9 {

10     int fd[2];

11     pid_t childpid;

12     char buf[100];

13

14     memset(buf,0,100);

15     //创建一个管道

16     if(pipe(fd) == -1)

17     {

18         perror("pipe() error");

19         exit(-1);

20     }

21     //创建一个子进程

22     childpid = fork();

23     if(childpid == 0)

24     {

25         printf("server input a message : ");

26         scanf("%s",buf);

27         //关闭读端

28         close(fd[0]);

29         write(fd[1],buf,strlen(buf));

30         exit(0);

31     }

32     if(childpid == -1)

33     {

34         perror("fork() error");

35         exit(-1);

36     }

37     //父进程关闭写端

38     close(fd[1]);

39     read(fd[0],buf,100);

40     printf("client read a message: %s\n",buf);

41     waitpid(childpid,NULL,0);

42     return 0;

43 }

程序执行结果如下:

上面程序的细节问题在于子进程需要关闭读端,父进程需要关闭写端。因为管道最早提出时候是单向,虽然现在有些系统提供全双工的管道。那么如何采用管道实现双向通信呢?很显然我们需要两个管道,控制两个不同的数据流向。现在有模拟一个Client和Server双向通信的过程,Client与Server之间可以相互发送和接收信息。此时需要两个管道进行模拟,管道1模拟Server写Client读数据流向,管道2模拟Client写Server读数据流向。代码如下所示:

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7

8 int main()

9 {

10     int fd1[2],fd2[2];

11     pid_t childpid;

12     char buf[100];

13

14     memset(buf,0,100);

15

16     if(pipe(fd1) == -1)

17     {

18         perror("pipe() error");

19         exit(-1);

20     }

21     if(pipe(fd2) == -1)

22     {

23         perror("pipe() error");

24         exit(-1);

25     }

26     childpid = fork();

27     if(childpid == 0)

28     {

29         printf("Server input a message : ");

30         gets(buf);

31         close(fd1[0]);

32         close(fd2[1]);

33         write(fd1[1],buf,strlen(buf));

34         read(fd2[0],buf,100);

35         printf("Server received message from client:%s\n",buf);

36         exit(0);

37     }

38     if(childpid == -1)

39     {

40         perror("fork() error");

41         exit(-1);

42     }

43     close(fd1[1]);

44     close(fd2[0]);

45     read(fd1[0],buf,100);

46     printf("Client receive a message from server: %s\n",buf);

47     printf("Client input a message : ");

48     gets(buf);

49     write(fd2[1],buf,strlen(buf));

50     waitpid(childpid,NULL,0);

51     return 0;

52 }

程序执行结果如下:

2 FIFO(first in first out)

FIFO又名有名管道,相对于上述管道而言。管道没有名字,因此只能在具有共同祖先进程的各个进程之间通信,无法在无亲缘关系的两个进程之间创建一个管道进行通信。为此有了FIFO,类似管道,也是一个单向(半双工)数据流,每个FIFO有一个路径名与之关联,从而允许无亲缘关系的进程访问同一个FIFO。FIFO有mkfifo函数创建。

#include

#include

int mkfifo(const char *pathname,mode_t mode); 成功返回0,出错返回-1。pathname是一个普通的路径名,是FIFO的名字,mode指定文件的权位。

在创建FIFO后,必须打开来读或者打开来写,不能打开来既读既写(因为FIFO是半双工)。现在采用FIFO实现上面的第二个例子,代码如下:

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9

10 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

11

12 #define FIFO1   "/tmp/fifo.1"

13 #define FIFO2   "/tmp/fifo.2"

14

15 int main()

16 {

17     int readfd,writefd;

18     pid_t   childpid;

19     char buf[100];

20     memset(buf,0,100);

21     //创建FIFO

22     if((mkfifo(FIFO1,FILE_MODE) < 0) && (errno != EEXIST))

23     {

24         perror("mkfifo() error");

25         exit(-1);

26     }

27     if((mkfifo(FIFO2,FILE_MODE) < 0) && (errno != EEXIST))

28     {

29         unlink(FIFO1);

30         perror("mkfifo() error");

31         exit(-1);

32     }

33      //创建子进程

34     childpid = fork();

35     if(childpid == 0)

36     {

37         readfd = open(FIFO1,O_RDONLY,0);

38         writefd = open(FIFO2,O_WRONLY,0);

39         printf("Server input a message: ");

40         gets(buf);

41         write(writefd,buf,strlen(buf));

42         read(readfd,buf,100);

43         printf("Server received a message from Client: %s\n",buf);

44         exit(0);

45     }

46     if(childpid == -1)

47     {

48         perror("frok() error");

49         exit(-1);

50     }

51      //防止死锁,注意顺序

52     writefd = open(FIFO1,O_WRONLY,0);

53     readfd = open(FIFO2,O_RDONLY,0);

54     read(readfd,buf,100);

55     printf("Client received a message form Server: %s\n",buf);

56     printf("Client input a mesage: ");

57     gets(buf);

58     write(writefd,buf,strlen(buf));

59     waitpid(childpid,NULL,0);

60     close(readfd);

61     close(writefd);

62     unlink(FIFO1);

63     unlink(FIFO2);

64     return 0;

65 }

运行结果如下:

上面的程序当中父进程打开FIFO的顺序不能颠倒,否则会造成死锁。因为在当前没有任何进程打开某个FIFO来写的时候,打开该FIFO来读的进程将会阻塞。交换父进程中两个open的调用顺序后,父子进程都将打开同一个FIFO进行读,而当前没有任何进程来打开该文件进行写,于是父子进程都阻塞,造成死锁。

下面采用FIFO实现无亲缘关系的两个进程之间的通信。Client与Server是两个独立的进程。

1 //共通文件fifo.h

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

10

11 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

12

13 #define FIFO1   "/tmp/fifo.1"

14 #define FIFO2   "/tmp/fifo.2"

1 //server进程 server.c

2 #include "fifo.h"

3

4 int main()

5 {

6     int readfd,writefd;

7     pid_t   childpid;

8     char buf[100];

9     memset(buf,0,100);

10     //创建FIFO

11     if((mkfifo(FIFO1,FILE_MODE) < 0) && (errno != EEXIST))

12     {

13         perror("mkfifo() error");

14         exit(-1);

15     }

16     if((mkfifo(FIFO2,FILE_MODE) < 0) && (errno != EEXIST))

17     {

18         unlink(FIFO1);

19         perror("mkfifo() error");

20         exit(-1);

21     }

22     readfd = open(FIFO1,O_RDONLY,0);

23     writefd = open(FIFO2,O_WRONLY,0);

24     printf("Server input a message: ");

25     gets(buf);

26     write(writefd,buf,strlen(buf));

27     read(readfd,buf,100);

28     printf("Server received a message from Client: %s\n",buf);

29     return 0;

30 }

1 //client进程 client。c

2 #include "fifo.h"

3

4 int main()

5 {

6     int readfd,writefd;

7     pid_t   childpid;

8     char buf[100];

9     memset(buf,0,100);

10     //创建FIFO

11     if((mkfifo(FIFO1,FILE_MODE) < 0) && (errno != EEXIST))

12     {

13         perror("mkfifo() error");

14         exit(-1);

15     }

16     if((mkfifo(FIFO2,FILE_MODE) < 0) && (errno != EEXIST))

17     {

18         unlink(FIFO1);

19         perror("mkfifo() error");

20         exit(-1);

21     }

22

23      //防止死锁,注意顺序

24     writefd = open(FIFO1,O_WRONLY,0);

25     readfd = open(FIFO2,O_RDONLY,0);

26     read(readfd,buf,100);

27     printf("Client received a message form Server: %s\n",buf);

28     printf("Client input a mesage: ");

29     gets(buf);

30     write(writefd,buf,strlen(buf));

31     close(readfd);

32     close(writefd);

33     unlink(FIFO1);

34     unlink(FIFO2);

35     return 0;

36 }

先执行server进程,然后执行client进程:结果如下:

以上介绍了管道和FIFO的操作方法。

参考资料:

《Unix环境高级编程》

阅读(2390) | 评论(0) | 转发(0) |

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值