2012-03-30 209 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複製過程中遇到的實際錯誤。