IPC - 如何将命令输出重定向到子级中的共享内存段

时间:2014-03-19 04:20:53

标签: linux ipc

我尝试将Unix命令输出重定向(写入)到子进程中的共享内存段, 然后让父进程从父进程中的同一共享内存段读回输出。经过几次徒劳的尝试后,我没有取得多少成功。有人能告诉我一个方法吗? 提前谢谢。

我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#define SHM_SIZE    1024

int main()
{
   key_t key; int  shmid; char* data;

   pid_t   cpid=fork();

   if (cpid<0) 
   {
         fprintf(stderr,"Fork error!\n");
         exit (-1);
   }
   else if (cpid==0)        // child process
   {
    if ((key = ftok("mysh.c", 'R')) == -1)
        { 
            perror("ftok");
            exit(1);
        }

    // Connect to shared memory 
    if ((shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1)
    {
       perror("shmget");
       exit(1);
    }

    // Attach to the segment
    data = shmat(shmid, (void *) 0, 0);
    if (data == (char *) (-1))
    {
       perror("shmat");
       exit(1);
    }

        system("ls -l");
    // Stuck: How to redirect the output of "ls -l"
    // to a shared memmory segment "data", so that parent process
    // can retrieve it later?? Tried to 
    // do pipe and dup2 but none worked.

    // Attempt via read?, but only garbage
    read(STDIN_FILENO, data, SHM_SIZE);

   }
   else 
   { // parent process
    int st;

    wait(&st);
    printf("Output read from the child:\n");
        if ((write(STDOUT_FILENO, data, SHM_SIZE)) < 0 )
        {
            perror("write 2");
            exit(1);
    }
   }
}

======================

2 个答案:

答案 0 :(得分:2)

    system("ls -l");
// Stuck: How to redirect the output of "ls -l"
// to a shared memmory segment "data", so that parent process
// can retrieve it later?? Tried to 
// do pipe and dup2 but none worked.

出于测试目的,我建议您阅读stdin,然后将其写入data


以下是使用POSIX共享内存(POSIX IPC API优于SYSV IPC API)的示例,该子类从stdin读取到共享内存区域,并且父级将此共享内存区域的内容写入{ {1}}:

stdout

注意:在这种情况下,这两个#include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <semaphore.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { const char *shm_name = "/dummy_cat_shm"; int shm_fd; off_t shm_length; const char *read_sem_name = "/dummy_cat_read"; const char *write_sem_name = "/dummy_cat_write"; sem_t *read_sem, *write_sem; pid_t pid; int buf_length; char *write_ptr, *read_ptr; buf_length = 1024; shm_length = sizeof(buf_length) + buf_length; /* Create semaphore */ read_sem = sem_open(read_sem_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 0); if (read_sem == SEM_FAILED) { perror("sem_open"); goto clean_up3; } write_sem = sem_open(write_sem_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 1); if (write_sem == SEM_FAILED) { perror("sem_open"); goto clean_up2; } /* Create shared memory segment */ shm_fd = shm_open(shm_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (shm_fd < 0) { perror("shm_open"); goto clean_up1; } if (ftruncate(shm_fd, shm_length) < 0) { perror("ftruncate"); goto clean_up0; } if ((pid = fork()) < 0) { perror("fork"); goto clean_up0; } else if (pid == 0) { write_ptr = mmap(NULL, shm_length, PROT_WRITE, MAP_SHARED, shm_fd, 0); if (write_ptr == MAP_FAILED) { perror("mmap"); goto clean_up0; } char *buf = write_ptr+sizeof(buf_length); while (sem_wait(write_sem) == 0) { if (fgets(buf, buf_length, stdin) != NULL) { *(int *)write_ptr = 1; sem_post(read_sem); } else { *(int *)write_ptr = 0; sem_post(read_sem); break; } } munmap(write_ptr, shm_length); } else { read_ptr = mmap(NULL, shm_length, PROT_READ, MAP_SHARED, shm_fd, 0); if (read_ptr == MAP_FAILED) { perror("mmap"); goto clean_up0; } char *buf = read_ptr + sizeof(buf_length); while (sem_wait(read_sem) == 0) { if (*(int *)read_ptr > 0) { printf("%s", buf); sem_post(write_sem); } else { break; } } munmap(read_ptr, shm_length); } clean_up0: shm_unlink(shm_name); clean_up1: sem_unlink(write_sem_name); clean_up2: sem_unlink(read_sem_name); clean_up3: exit(EXIT_FAILURE); } 可以放在mmap()之前。

编译:

fork()

运行:

gcc shm_exp.c -pthread -lrt

答案 1 :(得分:1)

如何重定向ls -l <​​/ strong>

的stdout

我们必须更多地了解此代码中涉及的进程(父级和子级)。 程序在运行期间创建了多少个进程? 正确答案是 - 。 两个进程是父进程和显式分叉子进程。 第三个是由系统(“ls -l”)调用创建的。 此函数隐式地分叉执行(通过调用exec系列函数)“ls -l”sell命令的另一个进程。您需要重定向的是 system()函数创建的子进程的输出。很遗憾,但 system()并未在参与者之间建立IPC。如果需要使用输出进行操作,请不要使用system()。

我同意@leeduhem, popen()可能是最好的方法。 它与 system()完全相同,即分叉新进程并执行“ls -l”。 此外,它还在参与者之间建立了一个管道IPC,因此很容易捕获子输出并随意使用它:

char buff[1024];
FILE *fd;

// instead of system("ls -l")
fd = popen("ls -l", "r");
// check for errors

while(fgets(buff, sizeof(buff), fd) != NULL)
{
  // write to the shared memory
}

pclose(fd); 

如果您不想使用 popen()功能,您可以编写类似的功能。 一般方法是

  1. 打开竖井()
  2. fork()一个新流程
  3. 使用dup2重定向标准输出
  4. 调用合适的 exec()函数(可能 execl())执行“ls -l”
  5. 从您正在复制的描述符中读取dup2。