管道和FIFO

来源:互联网 发布:sql select count 1 编辑:程序博客网 时间:2024/05/29 21:32

                                           管道和FIFO

    管道和FIFO是许多应用程序的基本构建模块。管道普遍用于shell中,不过也可以从程序中使用,往往用于从子进程向父进程回传消息。

     FIFO与管道类似,但他们是用mkfifo创建,之后需要用open打开。打开管道必须小心,因为许多规则制约着open的阻塞与否

     管道和FIFO的特征之一是他们的数据是一个字节流,类似于TCP连接。把这种字节流分割成各个记录的任何方法都得由应用程序来实现。

      一个简单的客户、服务器例子

      客户从标准输入读进一个路径名,并把它写入IPC通道。服务器从该IPC通道读出这个路径名,并尝试打开其文件来读。如果服务器可以打开该文件,他就读出其中的内容,并写入另一个IPC通道,以作为对客户的响应;否则,他就响应一个出错消息。客户随后从这个IPC通道读出响应,并把它写入标准输出。如果该服务器无法读该文件,那么客户读出的响应将是一个出错消息。否则,客户读出的响应将是该文件的内容。

       void client(int, int), server(int, int);

       int

       main(int argc, char **argv)
       {

             int pipe1[2], pipe2[2];

             pid_t  childpid;

             pipe(pipe1);

             pipe(pipe2);

             if((childpid = fork()) == 0)

             {

                   close(pipe1[1]);

                   close(pipe2[0]);

                   

                   server(pipe1[0], pipe2[1]);

                   exit(0);

              }

              close(pipe1[0]);

              close(pipe2[1]);

              client(pipe2[0], pipe1[1]);

              waitpid(childpid, NULL, 0);

              exit(0);

}

 

     void client(int readfd, int writefd)

     {

           size_t len;

           ssize_t n;

           char buf[MAXLINE];

           /*read pathname*/

           fgets(buf, MAXLINE, stdin);

           len = strlen(buf);

           /*delete new line from fgets()*/

           if(buf[len - 1] == '\n')

                len--;

          

           /*write pathname to IPC channel*/

           write(writefd, buff, len);

           /*read from IPC, write to standard output*/

           while(n = read(readfd, buff, MAXLINE));

                 write(STDOUT, buff, n);           

}

      void server(int readfd, int writefd)

      {

             int fd;

             ssize_t n;

             char buff[MAXLINE + 1];

             

             /*read from IPC channel*/

             if((n = read(readfd, buff, MAXLINE)) == 0)

                    err_quit("end of file while reading pathname");

             buff[n] = '\0';

             if((fd = fopen(buff, O_RDONLY)) < 0)

                   /*open error ,must tell client*/

             else if

             {

                    /*open success ,copy file to IPC channel*/

                    while((n = read(fd, buff, MAXLINE)) >0)

                        write(writefd,buff, n);

                    close(fd);

 

             }

}

 

      上例中,感觉像是两个管道两边连接着两个进程,然而实际上他们都是通过内核运作的。管道属于第二种共享内核中的数据。从客户到服务器以及从服务器到客户的所有数据都穿越了用户-内核接口两次:一次是在写入管道时一次是在读出管道时。

      全双工管道:整个管道只有一个缓冲区,在任意一个描述符上写入管道的任何数据都可以添加到该缓冲区的末尾,在任意一个描述符上从管道读出数据都是取自该缓冲区开头的数据、

      这个全双工其实是由两个半双工组成的,写入fd[1]的数据只能从fd[0]读。写入fd[0]的数据只能从fd[1]读出、

      popen和pclose函数

      popen函数:创建一个管道并启动另外一个进程,该进程要么从该管道读出标准输入,要么往该管道写入标准输出。

 

      FIFO

      管道没有名字,因此他们的最大劣势是只能用于有一个共同祖先进程的各个进程之间。我们无法在无亲缘关系的两个进程间创建一个管道并将他们用于IPC通道。

      FIFO指先进先出,UNIX中fifo类似于管道,他是一个单向数据流。不同于管道的是每个FIFO有一个路径名与之关联,从而允许无亲缘关系的进程访问同一个FIFO。

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

      第一个参数pathname是一个普通的Unix 路径名,他是该FIFO的名字。mode类似于open的第二个参数,

      在创建出一个FIFO后,他必须或者打开来读,或者打开来写,所用的可以是open函数,也可以是某个标准IO打开函数,FIFO不能打开来既读又写,因为他是半双工的。对管道或者FIFO的write调用总是往末尾添加数据,对他们的read则总是从开头返回数据、

      管道和FIFO的限制:

     (1)一个进程在任意时刻打开的最大描述符数。

     (2)可原子的写往一个管道或者FIFO的最大数据量。

         

     

       

0 0
原创粉丝点击