UNIX FIFO:如何只允许一个编写器/读卡器对使用FIFO?

时间:2010-05-30 14:44:12

标签: unix pipe fifo

我编写了两个程序:第一个是“编写器”,它创建了一个FIFO并将数据写入其中。第二个,“阅读器”在后台运行并在FIFO中查找数据。一旦有数据,读者就会读出来。

如果我开始,例如两个写入器和两个读取器,它们都可以写入/读入同一个FIFO。如何限制第3和第4个读/写器使用FIFO并且只允许一个写入器和一个读取器使用FIFO?

3 个答案:

答案 0 :(得分:4)

鉴于the code you posted in a separate answer,这是一个修改后的版本,修复了您遇到的问题。有关详细信息,请参阅注释,但简而言之:

  • 编写器检查mkfifo的返回值是否已检查,以查看是否已有另一位编写器创建了管道。
  • 读者在打开管道后获得管道上的独家咨询锁定(通过flock),以避免第一个读者删除管道之前第二个读者可以打开管道的竞争状态。

编剧:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>   /* needed for mkfifo */
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#define BUFFERSIZE 50
#define CHMOD 0777

int
main (int argc, char **argv)     
{  
    char outbuf[BUFFERSIZE];
    int fifo, j, anzahl;

    if (argc != 2)
    {                            
        printf("Ungültiger Parameter! Bsp.: ./fifow 10\n");  
        return 1;
    }

    anzahl=atoi(argv[1]);

    /* mkfifo fails if the file already exists, which means there's a
     * writer waiting for a reader.  This assures that only one writer
     * will write to the pipe, since it only opens the pipe if it was
     * the one who created it.
     */
    if (mkfifo("namedpipe4", CHMOD) == -1)
    {
        printf("namedpipe4 already exists\n");
        return 1;
    }

    fifo = open("namedpipe4", O_WRONLY);

    for (j = 0; j < anzahl; j++)
    {   
        printf("Writer PID: %d writes record nr. %6d\n", getpid(), j + 1);
        sprintf(outbuf, "Writer PID: %d writes record nr. %6d\n", getpid(), j + 1); 
        write(fifo, outbuf, BUFFERSIZE);       
        remove("namedpipe4");
        sleep(1);
    }

    close(fifo);

    exit(0);
}

阅读器:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>   /* for flock */
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#define BUFFERSIZE 50

int
main (int argc, char **argv)      
{  
    char inbuf[BUFFERSIZE];
    int fifo, var;

    printf("\n Waiting for a Pipe....\n");

    /* There are *two* ways the open can fail: the pipe doesn't exist
     * yet, *or* it succeeded, but a different writer already opened
     * it but didn't yet remove it.
     */
    while (1)
    {
        while ((fifo = open("namedpipe4", O_RDONLY)) == -1)
        {
            /* Since you didn't specify O_CREAT in the call to open, there
             * is no way that namedpipe4 would have been created by the
             * reader.  If there *is* now a namedpipe4, a remove here
             * would delete the one the writer created!
             */
            sleep(1);
        }    

        /* Get an exclusive lock on the file, failing if we can't get
         * it immediately.  Only one reader will succeed.
         */
        if (flock (fifo, LOCK_EX | LOCK_NB) == 0)
            break;

        /* We lost the race to another reader.  Give up and wait for
         * the next writer.
         */
        close (fifo);
    }

    /* We are definitely the only reader.
     */

    /* *Here* we delete the pipe, now that we've locked it and thus
     * know that we "own" the pipe.  If we delete before locking,
     * there's a race where after we opened the pipe, a different
     * reader also opened, deleted, and locked the file, and a new
     * writer created a new pipe; in that case, we'd be deleting the
     * wrong pipe.
     */
    remove("namedpipe4");

    while ((var = read(fifo, inbuf, BUFFERSIZE)) > 0)
    {    
        printf("Reader PID: %d reads  record: %s\n", getpid(), inbuf);
        /* No need to sleep; we'll consume input as it becomes
         * available.
         */
    }

    close(fifo);
    printf("\n EOF..\n");
    exit(0);
}

答案 1 :(得分:1)

使用pipe(2)创建FIFO,并且只有当FIFO从父进程分叉时,才会将FIFO的每一端的文件描述符提供给适当的进程。 (或者,让读者调用pipe(2)并分叉编写器,反之亦然。)由于FIFO永远不会存在于文件系统中,因此任何其他进程都无法访问它。

如果必须使用命名FIFO,请在读写器打开后删除FIFO。只要读者和作者打开它,底层FIFO仍然存在,但没有新的进程能够打开它。但是,会有一个竞争条件,第二个读取器或写入器可能会在删除它之前打开FIFO。

答案 2 :(得分:0)

FIFO Writer:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <fcntl.h>

#define BUFFERSIZE 50
#define CHMOD 0777



int main(int argc, char **argv)     
{  
   char outbuf[BUFFERSIZE]; // outbuffer
   int fifo, j, anzahl;
   // fifo - pipe file deskriptor, j - counter, anzahl - Parameter.

   if(argc!=2)               // Check if parameter is ok
   {                            
       printf("Ungültiger Parameter! Bsp.: ./fifow 10\n");  
       return 1;
   }

   anzahl=atoi(argv[1]);        // convert paramter to integer


   mkfifo("namedpipe4", CHMOD);         // make FIFO "namedpipe4"
   fifo = open("namedpipe4",O_WRONLY);      // open FIFO
   //
   for(j=0;j<anzahl;j++)
     {   

         printf("Writer PID: %d writes record nr. %6d\n", getpid(), j+1);
         sprintf(outbuf, "Writer PID: %d writes record nr. %6d\n", getpid(), j+1); 
         write(fifo, outbuf, BUFFERSIZE);       
         remove("namedpipe4");  // removing the fifo
         sleep(1);              // Wait 1 sec
     }

   close(fifo);  // 

   exit(0);

}

FIFO阅读器:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#define BUFFERSIZE 50

int main(void)      
{  

   char inbuf[BUFFERSIZE];  // inbuffer
   int fifo, var;

   printf("\n Waiting for a Pipe....\n");

   while((fifo = open("namedpipe4",O_RDONLY)) == -1) // while "there is no such pipe"
   {
    remove("namedpipe4");
    sleep(1);
   }    


   while((var = read(fifo, inbuf, BUFFERSIZE)) > 0) // while "i can read"
   {    
     printf("Reader PID: %d reads  record: %s\n", getpid(), inbuf);
     sleep(1);
   }



   close(fifo);     // 

   printf("\n EOF..\n");

   exit(0);


}