fork和exec之后在父级和子级之间共享文件描述符

tve*_*eeg 2 c linux fork file-descriptor exec

我在Linux,A和B上有两个进程.我想从进程A与进程B共享文件描述符,现在我只是将它序列化为a char*并将其传递给execl参数,但这不起作用.

Ac看起来像这样:

union descriptor{
    char c[sizeof(int)];
    int i;
} fd;
pid_t pid;

fd.i = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Perform other socket functions

pid = fork();
if(pid == 0){
    // Read data from socket
    if(execl("./B", fd.c, NULL) < 0){
        exit(EXIT_FAILURE);
    }else(
        exit(EXIT_SUCCESS);
    }
}else if(pid < 0){
    exit(EXIT_FAILURE);
}else{
    waitpid(pid, NULL, 0);
}
Run Code Online (Sandbox Code Playgroud)

Bc看起来像这样:

union descriptor{
    char c[sizeof(int)];
    int i;
} fd;

memcpy(&fd.c[0], argv[0], sizeof(int));

write(fd.i, "TEST", 4);
close(fd.i);
Run Code Online (Sandbox Code Playgroud)

但这不起作用,我不明白为什么不.我怎样才能做到这一点?如果它的工作原理,它是经过共享父母和孩子之间的文件描述符的最佳解决方案fork和一个exec

更新

问题与我提出的问题无关,它是由@OliCharlesworth指出的传递整数的错误方式引起的.请关闭这个问题.

nit*_*712 6

File descriptors are always passed between a parent and child process

当您fork进行处理时,在父进程中打开的文件描述符(在时间fork())被隐式传递给子进程.没有必要明确发送它们.

例如:

伪代码如下:

在过程A:

fd = open_socket_or_file;
char str_fd[3];
str_fd[0]=fd;
str_fd[1]=fd;
str_fd[2]=0;
if(fork()==0)
{
     execl("./B",str_fd,NULL);
}
Run Code Online (Sandbox Code Playgroud)

在子进程B中,您可以执行以下操作:

int fd = argv[1][0];
/* now do whatever you want with the fd...*/
Run Code Online (Sandbox Code Playgroud)

编辑:

如果进程不同,则需要显式传递文件描述符.这通常使用UNIX-Domain套接字完成(如果您使用的是Linux Flavors).对于与此相关的代码,您可以看到此答案

  • @ThomasVersteeg是的,我回答了! (2认同)

小智 5

是的,即使在 fork 或 exec 或 fork 和 exec 之后,文件描述符仍然保持打开状态。您只需要知道使用 exec 替换的新进程映像中的 fd 值,否则将该 fd 放在已知的进程映像上该过程(例如:0,1,2)。所以你可以通过两种方式做到这一点:

  • 使用 dup2 将 fd 放置在任一标准文件描述符上(注意:据我所知,您将无法重置实际上已知的标准文件描述符)

  • 将 fd 作为字符串参数传递给 6 个 exec 函数之一即可完成这项工作

因此,如果您希望保留标准 fds,我建议您使用第二种方法

这是两种实现方法:

P1.c(使用参数传递)

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
void main()
{
    printf("Hello this is process 1\n");
    int fd=open("./foo",O_RDONLY);
    char buf[255];
    //int n=read(fd,buf,255);
    int h=fork();
    if(h==0)
    {
        char *fname="./p2";
        char *arg[3];
        char targ[10];
        sprintf(targ,"%d",fd);
        arg[0]=fname;
        arg[1]=targ;
        arg[2]=NULL;
        execvp(fname,arg);
    }
    else
    {
        printf("This is from p1 process\n");
        //write(1,buf,strlen(buf));
                    //do some process with p1
        printf("This is end of p1 process\n");
    }
}
Run Code Online (Sandbox Code Playgroud)

P1.c(使用 dup2 带 0)

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
void main()
{
    printf("Hello this is process 1\n");
    int fd=open("./foo",O_RDONLY);
    int h=fork();
    if(h==0)
    {
        dup2(fd,0);//note we will be loosing standard input in p2
        execvp(fname,NULL);
    }
    else
    {
        printf("This is from p1 process\n");
        //write(1,buf,strlen(buf));
                    //do some process with p1
        printf("This is end of p1 process\n");
    }
}
Run Code Online (Sandbox Code Playgroud)

P2.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main(int argc,char *argv[])
{
    int fd=atoi(argv[1]);      //here fd=0 in case dup2 in process ps1.c
    char buf[1024];
    int n=read(fd,buf,1024);
    buf[n]='\0';
    printf("This is from p2\n");
    write(1,buf,strlen(buf));
}
Run Code Online (Sandbox Code Playgroud)