2012-03-30 164 views
1

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

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

在此先感谢。

回答

1

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

另一个是通过一个Unix域套接字发送文件描述符sendmsg;看到这个例子程序,功能send_connection。请注意,文件描述符在接收过程中可能有不同的编号,因此您可能需要执行一些dup2魔术才能使它们在共享内存中正确显示。

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

+0

dup是否跨过程?这是一个进程可以重复其他进程'fd(指向它想指向的同一个文件),然后开始使用新的fd? – 2012-04-02 09:42:57

+0

@SunandaSharma:不,在一个过程中克隆fds。我的意思是你必须同步各个进程中的fds的实际数字,然后使用'dup2'将它们设置为跨进程相同。 – 2012-04-02 09:49:42

+0

哦,好吧。那么这个设置将不能为我工作,不幸的是。非常感谢您的投入:) – 2012-04-02 10:04:50

0

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

这里的建议补丁:

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

(目前,该补丁仅增加了86/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复制过程中遇到的实际错误。