Linux IPC-如何将命令输出重定向到子系统中的共享内存段
我试图将Unix命令输出重定向(写入)到子系统中的共享内存段, 然后让父进程从父进程中的同一共享内存段读回输出。在几次徒劳的尝试之后,我没有取得多少成功。谁能给我指路吗? 提前谢谢 我的代码:Linux IPC-如何将命令输出重定向到子系统中的共享内存段,linux,ipc,Linux,Ipc,我试图将Unix命令输出重定向(写入)到子系统中的共享内存段, 然后让父进程从父进程中的同一共享内存段读回输出。在几次徒劳的尝试之后,我没有取得多少成功。谁能给我指路吗? 提前谢谢 我的代码: #包括 #包括 #包括 #包括 #定义SHM_大小1024 int main() { key\u t key;int shmid;char*数据; pid_t cpid=fork(); 若有(消费物价指数) 出于测试目的,我建议您阅读stdin,然后将它们写入数据中 下面是一个使用POSIX共享内存的示
#包括
#包括
#包括
#包括
#定义SHM_大小1024
int main()
{
key\u t key;int shmid;char*数据;
pid_t cpid=fork();
若有(消费物价指数)
出于测试目的,我建议您阅读stdin
,然后将它们写入数据中
下面是一个使用POSIX共享内存的示例(POSIX IPC API优于SYSV IPC API),其中子级从stdin
读取共享内存区域,父级将此共享内存区域的内容写入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);
}
运行:
$ ls / | ./a.out
bin/ home/ lib32/ mnt/ run/ sys/ vmlinuz@
boot/ initrd.img@ lib64/ opt/ sbin/ tmp/ vmlinuz.old@
dev/ initrd.img.old@ lost+found/ proc/ selinux/ usr@
etc/ lib/ media/ root/ srv/ var/
出于测试目的,我建议您阅读stdin
,然后将它们写入数据中
下面是一个使用POSIX共享内存的示例(POSIX IPC API优于SYSV IPC API),其中子级从stdin
读取共享内存区域,父级将此共享内存区域的内容写入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);
}
运行:
$ ls / | ./a.out
bin/ home/ lib32/ mnt/ run/ sys/ vmlinuz@
boot/ initrd.img@ lib64/ opt/ sbin/ tmp/ vmlinuz.old@
dev/ initrd.img.old@ lost+found/ proc/ selinux/ usr@
etc/ lib/ media/ root/ srv/ var/
如何重定向ls-l的stdout
我们必须对这段代码中涉及的过程(父级和子级)有更多的了解。
您的程序在运行期间创建了多少个进程?
正确答案是三个。
两个进程是父进程和显式分叉子进程。
第三个是由系统(“ls-l”)调用创建的。
此函数隐式派生另一个进程,该进程通过调用exec系列函数执行“ls-l”sell命令。您需要重定向的是由system()函数创建的子进程的输出。这很遗憾,但是system()不在参与者之间建立IPC。如果需要操作输出,请不要使用system()
我同意@leeduhem,popen()可能是最好的方法。
它的工作原理与系统()完全相同,即派生一个新进程并执行“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()函数,可以编写类似的函数。
一般做法是
打开一个管道()
fork()新流程
使用dup2重定向标准输出
调用执行“ls-l”的合适的exec()函数(可能是execl())
从dup2复制的描述符中读取
如何重定向ls-l的stdout
我们必须对这段代码中涉及的过程(父级和子级)有更多的了解。
您的程序在运行期间创建了多少个进程?
正确答案是三个。
两个进程是父进程和显式分叉子进程。
第三个是由系统(“ls-l”)调用创建的。
此函数隐式派生另一个进程,该进程通过调用exec系列函数执行“ls-l”sell命令。您需要重定向的是由system()函数创建的子进程的输出。这很遗憾,但是system()不在参与者之间建立IPC。如果需要操作输出,请不要使用system()
我同意@leeduhem,popen()可能是最好的方法。
它的工作原理与系统()完全相同,即派生一个新进程并执行“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()函数,可以编写类似的函数。
一般做法是
打开一个管道()
fork()新流程
使用dup2重定向标准输出
调用执行“ls-l”的合适的exec()函数(可能是execl())
从dup2复制的描述符中读取
为什么不使用管道让父进程读取子进程的输出?我想学习/练习的练习是共享内存段。我想知道,将其管道化到文件描述符,然后再次将其从fd重新定向到共享内存缓冲区,是否可以完成这项工作。这听起来是多余的,不确定。如果使用管道,共享内存是不必要的ry.这是一种更简单、更正常的方法。为什么不为父进程使用管道来读取子进程的输出?我想学习/练习的练习是共享内存段。我想知道,将其管道化到文件描述符,然后再次将其从fd重新定向到共享内存缓冲区,是否可以完成这项工作。这听起来是多余的,n当然可以。如果你使用管道,共享内存是不必要的。这是一个更容易和正常的方式来做到这一点。