C语言 我可以将文件描述符共享给 linux 上的另一个进程还是它们是进程本地的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2358684/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I share a file descriptor to another process on linux or are they local to the process?
提问by live2dream95
Say I have 2 processes, ProcessA and ProcessB. If I perform int fd=open(somefile)in ProcessA, can I then pass the value of file descriptor fdover IPC to ProcessB and have it manipulate the same file?
假设我有 2 个进程,ProcessA 和 ProcessB。如果我int fd=open(somefile)在 ProcessA 中执行,那么我可以fd通过 IPC 将文件描述符的值传递给 ProcessB 并让它操作同一个文件吗?
回答by nos
You can pass a file descriptor to another process over unix domainsockets. Here's the code to pass such a file descriptor, taken from Unix Network Programming
您可以通过unix 域套接字将文件描述符传递给另一个进程。这是传递此类文件描述符的代码,取自Unix Network Programming
ssize_t
write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
{
struct msghdr msg;
struct iovec iov[1];
#ifdef HAVE_MSGHDR_MSG_CONTROL
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
*((int *) CMSG_DATA(cmptr)) = sendfd;
#else
msg.msg_accrights = (caddr_t) &sendfd;
msg.msg_accrightslen = sizeof(int);
#endif
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
return(sendmsg(fd, &msg, 0));
}
/* end write_fd */
And here's the code to receive the file descriptor
这是接收文件描述符的代码
ssize_t
read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
{
struct msghdr msg;
struct iovec iov[1];
ssize_t n;
int newfd;
#ifdef HAVE_MSGHDR_MSG_CONTROL
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
#else
msg.msg_accrights = (caddr_t) &newfd;
msg.msg_accrightslen = sizeof(int);
#endif
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
if ( (n = recvmsg(fd, &msg, 0)) <= 0)
return(n);
#ifdef HAVE_MSGHDR_MSG_CONTROL
if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&
cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
if (cmptr->cmsg_level != SOL_SOCKET)
err_quit("control level != SOL_SOCKET");
if (cmptr->cmsg_type != SCM_RIGHTS)
err_quit("control type != SCM_RIGHTS");
*recvfd = *((int *) CMSG_DATA(cmptr));
} else
*recvfd = -1; /* descriptor was not passed */
#else
/* *INDENT-OFF* */
if (msg.msg_accrightslen == sizeof(int))
*recvfd = newfd;
else
*recvfd = -1; /* descriptor was not passed */
/* *INDENT-ON* */
#endif
return(n);
}
/* end read_fd */
回答by kay - SE is evil
If both processes belong the the same user, then you can simply make use of the procfs.
如果两个进程属于同一个用户,那么您可以简单地使用 procfs。
char fd_path[64]; // actual maximal length: 37 for 64bit systems
snprintf(fd_path, sizeof(fd_path), "/proc/%d/fd/%d", SOURCE_PID, SOURCE_FD);
int new_fd = open(fd_path, O_RDWR);
Of course you would need to some IPC mechanism to share the value of SOURCE_FD. See e.g. “Linux C: upon receiving a signal, is it possible to know the PID of the sender?”.
当然,您需要一些 IPC 机制来共享SOURCE_FD. 参见例如“ Linux C:在接收到信号时,是否有可能知道发送者的 PID?”。
回答by MarkR
You can use the method nos described in this thread, or the (more conventional) way, by sharing it between related processes (typically parent-child or siblings) by having it created, the forked processes automatically receive a copy.
您可以使用此线程中描述的方法 nos 或(更传统的)方式,通过创建它在相关进程(通常是父子或兄弟)之间共享它,分叉的进程会自动接收一个副本。
Indeed, forked processes get all your FDs and can use them unless they close them (which is generally a good idea).
事实上,分叉进程获得了你所有的 FD 并且可以使用它们,除非它们关闭它们(这通常是一个好主意)。
Therefore if a parent forks two children, if they both have a file descriptor they didn't close, it is now shared (even if the parent subsequently closes it). This could, for example, be a pipe from one child to another. This is how shell redirects like
因此,如果父母派生了两个孩子,如果他们都有一个他们没有关闭的文件描述符,那么它现在是共享的(即使父母随后关闭了它)。例如,这可以是从一个孩子到另一个孩子的管道。这就是shell重定向的方式
ls -l | more
Work.
工作。
回答by Stef Bon
Note that in the example of above, the setting of variables when receiving, like:
注意上面的例子中,接收时的变量设置,如:
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
is not required. The whole idea of a message structure with headers is that the receiving site does not have to know what it reads, and can by checking the (first) header, what kind of message it is and what to expect.
不需要。带有标题的消息结构的整个想法是接收站点不必知道它读取的是什么,并且可以通过检查(第一个)标题,它是什么类型的消息以及期望什么。

