我在Linux上有两个进程,A& B.
我想与进程B共享进程A中的文件描述符,现在我只是将其序列化为char*
并将其传递给execl
参数,但这不起作用。
A.c看起来像这样:
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);
}
B.c看起来像这样:
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);
但这不起作用,我真的不明白为什么不行。我怎样才能做到这一点?如果它有效,它是在fork
和exec
之后在父母和孩子之间共享文件描述符的最佳解决方案吗?
问题与我提出的问题无关,它是由@OliCharlesworth指出的传递整数的错误方式引起的。请关闭这个问题。
答案 0 :(得分: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);
}
在子流程 B 中,您可以执行以下操作:
int fd = argv[1][0];
/* now do whatever you want with the fd...*/
修改强>
如果进程不同,则需要传递文件描述符显式。这通常使用UNIX-Domain套接字完成(如果您使用的是Linux Flavors)。对于与此相关的代码,您可以看到this answer
答案 1 :(得分:3)
是的,即使在fork或exec或fork和exec之后文件描述符仍保持打开。你只需要知道在使用exec替换的新进程映像中fd的值将else放入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");
}
}
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");
}
}
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));
}