關於linux進程間的close-on-exec機制

來源:互聯網
上載者:User

標籤:linux   連接埠佔用   sock_cloexec   close-on-exec   fd_cloexec   

轉載請註明出處:簾卷西風的專欄(http://blog.csdn.net/ljxfblog)

前幾天寫了一篇部落格,講述了連接埠佔用情況的查看和解決。

關於linux系統連接埠查看和佔用的解決方案

大部分這種問題都能夠解決,在文章的最後,提到了一種特殊情況,就是父子進程中的連接埠佔用情況。父進程監聽一個連接埠後,fork出一個子進程,然後kill掉父進程,再重啟父進程,這個時候提示連接埠佔用,用netstat查看,子進程佔用了父進程監聽的連接埠。

原理其實很簡單,子進程在fork出來的時候,使用了寫時複製(COW,Copy-On-Write)方式獲得父進程的資料空間、 堆和棧副本,這其中也包括檔案描述符。剛剛fork成功時,父子進程中相同的檔案描述符指向系統檔案表中的同一項(這也意味著他們共用同一檔案位移量)。這其中當然也包含父進程建立的socket。

接著,一般我們會調用exec執行另一個程式,此時會用全新的程式替換子進程的本文,資料,堆和棧等。此時儲存檔案描述符的變數當然也不存在了,我們就無法關閉無用的檔案描述符了。所以通常我們會fork子進程後在子進程中直接執行close關掉無用的檔案描述符,然後再執行exec。

但是在複雜系統中,有時我們fork子進程時已經不知道開啟了多少個檔案描述符(包括socket控制代碼等),這此時進行逐一清理確實有很大難度。我們期望的是能在fork子進程前開啟某個檔案控制代碼時就指定好:“這個控制代碼我在fork子進程後執行exec時就關閉”。其即時有這樣的方法的:即所謂 的 close-on-exec。

回到我們的應用情境中來,只要我們在建立socket的時候加上SOCK_CLOEXEC標誌,就能夠達到我們要求的效果,在fork子進程中執行exec的時候,會清理掉父進程建立的socket。

#ifdef WIN32SOCKET ss = ::socket(PF_INET, SOCK_STREAM, 0);#elseSOCKET ss = ::socket(PF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);#endif
當然,其他的檔案描述符也有類似的功能,例如檔案,可以在開啟的時候使用O_CLOEXEC標識(linux 2.6.23才開始支援此標記),達到和上面一樣的效果。或者使用系統的fcntl函數設定FD_CLOEXEC即可。

//方案Aint fd = open(“foo.txt”,O_RDONLY);int flags = fcntl(fd, F_GETFD);flags |= FD_CLOEXEC;fcntl(fd, F_SETFD, flags);//方案B,linux 2.6.23後支援int fd = open(“foo.txt”,O_RDONLY | O_CLOEXEC);
好了,現在我們終於可以完美的解決連接埠佔用這個令人煩惱的問題了。



關於linux進程間的close-on-exec機制

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.