不使用pipe()获取两个文件描述符

时间:2012-07-18 09:54:31

标签: c linux pipe shared-memory

我正在尝试理解命令pipe(2),例如:

int pipefd[2];
if (pipe(pipefd) == -1) {
    perror("pipe");
    exit(EXIT_FAILURE);
}

我希望获得两个带有shared memory的文件描述符,用于匿名管道(父子关系)。

例如,这是父子进程之间的简单对话:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/wait.h>  
#include <unistd.h>    
#include <string.h>   
#define SHMSIZE 16
int main() {
   int shmid;
   char *shm;

   if(fork() == 0)   // child first

   {

      shmid = shmget(2009, SHMSIZE, 0);
      shm = shmat(shmid, 0, 0);
      char *s = (char *) shm;
      *s = '\0';
      int i;

      // child enters the input that would be stored in the shared memory
      for(i=0; i<3; i++) {
         int n;
         printf("Enter number<%i>: ", i);
         scanf("%d", &n);

         // convert the input into a c-string
         sprintf(s, "%s%d", s, n);
      }
      strcat(s, "\n");

      // display the contents of the shared memory
      printf ("I'm the child process , and I wrote:%s\n",shm);

      // detaches the shared memory segment
      shmdt(shm);
   }


   else   // parent

   {

       // get the segment
      shmid = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);

      // attaching the segment to the father
      shm = shmat(shmid, 0, 0);

      // father waits for the son the finish
      wait(NULL);

      // father displays what the son wrote
      printf ("I'm the father , and my child wrote :%s\n",shm) ;

      // detaches the shared memory segment
      shmdt(shm);

      shmctl(shmid, IPC_RMID, NULL);
   }
   return 0;
}

输出非常简单:

Enter number<0>: 123
Enter number<1>: 567
Enter number<2>: 789
I'm the child process , and I wrote:123567789

I'm the father , and my child wrote :123567789

这是shm_pipe_pipe()的实施,替代pipe(2)

int shm_pipe_pipe(int spd[2])
{
    spd[0] = shmget(2009, SHMSIZE, 0);
    spd[1] = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);

     if (spd[0] == -1 || spd[1] == -1)
         return -1;
     return 1;

}

我的问题是:

  1. 我知道fd[0]用于阅读而fd[1]用于写作,但是 他们究竟拥有什么?地址?

  2. 我上面写的函数shm_pipe_pipe似乎不起作用,它有什么问题?

  3. 由于 `

1 个答案:

答案 0 :(得分:8)

  1. 回答第一个问题,他们持有文件描述符。他们不是地址。它们是表的索引。该表实际上具有将由内核解释的地址(文件系统,如果描述符是磁盘文件,网络堆栈,如果它是网络套接字等)。永远不会给文件的用户提供实际地址。只有包含实际地址的表的索引才会提供给用户。该表的结构非常复杂,各种子系统不同。但基本概念是相对相同的。
  2. 以下图片对磁盘文件有效。

    This image is valid for disk files

    如果有两个独立的过程:

    Two independent process

    如果是管道..

    This is how Pipe works, its just two file descriptors

    这是文件描述符表的一般视图 FDT

    1. 您的第二个问题,似乎您正在尝试从pipefd返回的值填充文件描述符数组shmget()
    2. 来自man 2 shmget

        

      shmget()返回共享内存段的标识符   与参数键的值相关联。一个新的共享内存   段,大小等于大小的值四舍五入到倍数   如果key的值为IPC_PRIVATE或key不是,则创建PAGE_SIZE   IPC_PRIVATE,不存在与密钥对应的共享内存段,以及   IPC_CREAT在shmflg中指定。

      了解shmget()的作用非常重要。它要求舍入大小(usnig系统的PAGE_SIZE)。这段内存由密钥标识。因此内核维护一个密钥值表。该表还包含共享内存区域的地址。现在,当您调用shmat()时,您使用shmid查询此表,并且返回的地址附加了您的进程地址空间。

      因此shmid返回的shmget()是系统维护的键值对表中的条目,与pipe()使用的文件描述符无关。

      底线是:

      你无法以这种方式实施pipe。你为什么不看看pipe本身的实际实现?

      http://sourceware.org/git/?p=glibc.git;a=blob;f=io/pipe.c;h=07a37ae778046e56c13e62fd2a2fa678f5546424;hb=HEAD

      虽然该文件中没有任何用处,因为它只调用其他__pipe。您可以克隆git repo并使用cscope查找pipe的实际实现。