2017-08-17 96 views
1

此問題與a question about getting a free port in Haskell有關,其中我包含getFreePort函數,該函數檢索第一個可用端口。此功能適用於Windows系統,但當我在我的Linux機器上嘗試時,它隨機失敗(空閒端口被報告爲繁忙)。爲什麼重新綁定到套接字將會隨機失敗?

我修改嘗試綁定重新到任意地址的功能,而且它隨機失敗:

getFreePort :: IO Integer 
getFreePort = do 
    sock <- socket AF_INET Stream defaultProtocol 
    bind sock (SockAddrInet aNY_PORT iNADDR_ANY) 
    port <- socketPort sock 
    close sock 
    print "Trying to rebind to the sock" 
    sock <- socket AF_INET Stream defaultProtocol 
    bind sock (SockAddrInet port 0x0100007f) 
    port <- socketPort sock 
    close sock 
    return (toInteger port) 

我明白,有對其他進程的競爭條件收購該端口,但這不可能嗎?

+6

獲得一個空閒端口後,爲什麼要關閉用來獲取它的套接字?不要這樣做。只需使用相同的套接字,不要創建新的套接字並將其綁定到同一端口,這確實是競爭條件。關閉前一個套接字會將端口置於'TIME_WAIT'狀態,除非您使用'SO_REUSEADDR' /'SO_REUSEPORT'套接字選項 –

+0

,否則它會在一段時間內無法重用。問題是我必須將端口號傳遞給兩個將在該端口上通信的外部進程。這就是爲什麼我必須關閉它。 –

+1

這兩個進程爲什麼不是自己獲取端口並相互協調?你爲什麼在第三個過程中這樣做?您無法獲取端口然後關閉它,然後期望進程能夠使用它。你需要重新思考你的方法。 –

回答

3

作爲一般性評論,check if a resource is available and if so take it的模式往往是反模式。每當你這樣做時,你就會冒着另一個進程在檢查之後但在你自己實際獲得它之前冒這個資源的風險。

您經過這樣的檢查後唯一的信息是該資源未在該特定時間點使用。它可能會或可能不會幫助您猜測未來端口的狀態,但您擁有的信息在任何時候都不受約束。你不能認爲,因爲該資源在時間t是免費的,它仍然是免費的在t+dt。即使dt非常小。當你問快速時,它可能更有可能是免費的。但就是這樣 - 可能性更高。

您應該嘗試獲取資源並正確處理故障。確保一個端口真正免費的唯一方法就是當您成功打開它時。然後你知道它確實是免費的。一旦你關閉它,所有的投注都會再次關閉。

我不認爲你可以安全地檢查一個進程中的端口是否空閒,然後假設它在另一個進程中仍然是空閒的。那沒有意義。在同一個過程中它甚至沒有意義!

至少,你就必須設計一個協議,該協議會來回走:

  1. 這裏是這僅僅是免費的端口,嘗試
  2. 不,它採取現在
  3. OK ,這裏的另外一個
  4. 不,現在是採取
  5. 好,這裏是另外一個
  6. 是的,知道了,謝謝

但這是非常愚蠢的開始。需要該端口的進程應該打開它。當它已經打開端口而沒有打開端口時,則應該將端口號傳送給對方。