困擾了許久的一個問題:父子進程共享文件描述符或者說父子進程傳遞文件描述符問題 今天終於解決了!!!因此,記錄一下。
一、問題描述:
在linux系統,我有一個A程序,使用socket函數打開並綁定了本地端口假設是5555,然後A程序執行一個sh腳本文件,這個腳本文件會將B程序運行起來。結果,查詢端口占用情況時,A,B兩個程序都在監聽5555端口。即A程序啓動B程序時,端口發生了傳遞。我的問題是,怎樣才能防止端口傳遞?
在Windows系統,我有一個A程序,使用socket函數打開並綁定了本地端口假設是5555,然後A程序用CreateProcess啓動一個B程序。然後用任務管理器將A程序強殺,再次啓動A程序,發現A程序無法正常啓動了,提示端口已經被佔用,無法打開。將B程序退出運行後,再啓動A程序,此時A程序可以正常啓動。我的問題是,怎樣才能防止端口傳遞?
二、 解決辦法:
1)創建socket時,如果是linux系統,設置FD_CLOEXEC標誌位,核心代碼如下:
int m_sock = socket(AF_INET, SOCK_STREAM, 0);
if (m_sock == -1)
{
printf("create socket failed:%s\n",strerror(errno));
}
::fcntl(m_sock, F_SETFD, FD_CLOEXEC);
2)創建socket時,如果是Windows系統,使用SetHandleInformation設置HANDLE_FLAG_INHERIT標誌位,核心代碼如下:
SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
3)我寫了一個Windows和linux設置屬性的函數,如下:
//Windows和linux
void mg_set_close_on_exec(sock_t sock) {
#if defined(_WIN32) && !defined(WINCE)
(void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
#elif defined(__unix__)
fcntl(sock, F_SETFD, FD_CLOEXEC);
#else
(void) sock;
#endif
}
三、問題擴展
注:libevent庫沒有處理句柄傳遞和文件描述符傳遞的問題。
SetHandleInformation函數介紹來自百度百科:
函數
SetHandleInformation函數:
[函數功能]
控制哪些子進程能繼承內核對象句柄,可調用SetHandleInformation函數改變內核對象句柄的繼承標誌。
[函數原型聲明]
BOOL WINAPI SetHandleInformation(
_In_ HANDLE hObject,
_In_ DWORD dwMask,
_In_ DWORD dwFlags
);
參數說明
第一個參數hObject標識了一個有效句柄。
第二個參數dwMask告訴函數我們想更改哪個或者哪些標誌:
1\ HANDLE_FLAG_INHERIT 用CreateProcess(bInheritHandle設爲TRUE)創建出來的子進程可以繼承對象句柄
2\HANDLE_FLAG_PROTECT_FROM_CLOSE 無法調用CloseHandle關閉對象句柄
第三個參數dwFlags指出希望把標誌設成什麼。
實例
例如,要打開一個內核對象句柄的繼承標誌,可以像下面這樣寫:
SetHandleInformation( hObj, HANDLE_FLAG_INHERIT ,HANDLE_FLAG_INHERIT );
要關閉這個標誌,可以像下面這樣寫:
SetHandleInformation( hObj , HANDLE_FLAG_INHERIT , 0)