跨进程共享文件描述符

时间:2012-03-30 09:11:43

标签: file shared-memory

我想为多个独立进程设置共享内存环境。在我想要共享的数据结构中,还有每个进程的连接fds。

我想知道我们是否有办法分享这些fds?或使用全球fds或类似的东西?

提前致谢。

2 个答案:

答案 0 :(得分:1)

在Unix主机上共享文件描述符有两种方法。一种方法是让子进程通过fork继承它们。

另一个是通过sendmsg的Unix域套接字发送文件描述符;请参阅此示例程序,函数send_connection(已归档here)。请注意,文件描述符在接收过程中可能具有不同的编号,因此您可能必须执行一些dup2魔法才能使它们在共享内存中正确显示。

如果不这样做,共享内存区域中的文件描述符将只是整数。

答案 1 :(得分:0)

最近,我不得不解决类似于OP所描述的问题。为此,我提出了一个专门的系统调用(我可能会添加一个非常简单的系统调用),将文件描述符直接发送到协作进程地址,并依赖Posix.1b信号队列作为传递介质(作为额外的好处,例如这种方法本质上不受“fd recursion" attack”的影响,它在某种程度上困扰了所有基于VFS的机制。)

这是建议的补丁:

http://permalink.gmane.org/gmane.linux.kernel/1843084

(目前,该补丁仅为x86 / x86_64架构添加了新的系统调用,但将其连接到其他架构是微不足道的,没有使用平台依赖的功能)。

操作理论如下。发送方和接收方都需要就一个或多个信号编号达成一致,以用于描述符传递。那些必须是Posix.1b信号,这保证了可靠的传递,因此SIGRTMIN偏移。此外,如果需要进行优先级管理,较小的信号编号具有较高的传送优先级:

int signo_to_use = SIGRTMIN + my_sig_off;

然后,发起进程调用系统调用:

int err = sendfd(peer_pid, signo_to_use, fd_to_send);

就是这样,发件人方面没有必要做其他事情。显然,sendfd()只有在原始进程有权发出目标进程信号并且目标进程没有阻塞/忽略信号的情况下才会成功。

还必须注意,sendfd()永远不会阻止;如果目的地进程'它将立即返回信号队列已满。在一个设计良好的应用程序中,这将表明目标进程无论如何都有问题,或者还有太多的工作要做,因此应该生成新的工作人员/丢弃工作项目。过程的大小'可以使用rlimit()配置信号队列,与可用文件描述符的数量相同。

接收过程可以安全地忽略该信号(在这种情况下,不会发生任何事情,并且几乎不会在内核端产生任何开销)。但是,如果接收进程想要获取传递的文件描述符,那么它所需要的只是使用sigtimedwait() / sigwaitinfo()或更通用的signalfd()来收集信号信息:

/* First, the receiver needs to specify what it is waiting for: */
sigset_t sig_mask;
sigemptyset(&sig_mask);
sigaddset(&sig_mask, signo_to_use);

siginfo_t sig_info;
/* Then all it needs is to wait for the event: */
sigwaitinfo(&sig_mask, sig_info);

成功返回sigwaitinfo()后,sig_info.si_int将包含新文件描述符,指向同一IO对象,作为原始进程发送的文件描述符。 sig_info.si_pid将包含原始流程' PID和sig_info.si_uid将包含原始流程' UID。如果sig_info.si_int小于零(表示无效的文件描述符),sig_info.si_errno将包含errno,表示在fd复制过程中遇到的实际错误。