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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:41:56  来源:igfitidea点击:

Can I share a file descriptor to another process on linux or are they local to the process?

clinux

提问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.

不需要。带有标题的消息结构的整个想法是接收站点不必知道它读取的是什么,并且可以通过检查(第一个)标题,它是什么类型的消息以及期望什么。