管道和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];1314     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];1314     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#includeint 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 910 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)1112 #define FIFO1   "/tmp/fifo.1"13 #define FIFO2   "/tmp/fifo.2"1415 int main()16 {17     int readfd,writefd;18     pid_t   childpid;19     char buf[100];20     memset(buf,0,100);21     //创建FIFO22     if((mkfifo(FIFO1,FILE_MODE)23     {24         perror("mkfifo() error");25         exit(-1);26     }27     if((mkfifo(FIFO2,FILE_MODE)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 #include1011 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)1213 #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     //创建FIFO11     if((mkfifo(FIFO1,FILE_MODE)12     {13         perror("mkfifo() error");14         exit(-1);15     }16     if((mkfifo(FIFO2,FILE_MODE)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     //创建FIFO11     if((mkfifo(FIFO1,FILE_MODE)12     {13         perror("mkfifo() error");14         exit(-1);15     }16     if((mkfifo(FIFO2,FILE_MODE)17     {18         unlink(FIFO1);19         perror("mkfifo() error");20         exit(-1);21     }2223      //防止死锁,注意顺序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环境高级编程》
10-31 08:35
查看更多