2012-08-16 149 views
2

我想使用fsockopen()來檢查Selenium服務器是否正在運行。當服務器運行時,應該設置常量。當它不是常數沒有設置。這是通過使用以下代碼完成的:PHP - fsockopen()超時而不是返回false?

if(!defined('TEST_SELENIUM')){ 
    $fp = @fsockopen('localhost', 4444); 
    if ($fp !== false) { 
     define('TEST_SELENIUM', true); 
     fclose($fp); 
    } 
} 

當服務器未運行(在Windows 7上)時出現問題。而不是fsockopen()從找到一個封閉的端口返回false,它試圖與端口進行通信。當服務器運行時,它使用netstat快速顯示。當服務器關閉時,netstat不會從端口4444返回任何東西。從我對fsockopen()的理解,這應該立即返回false。但是,它再次試圖與港口溝通。我不想在這裏添加一個超時,因爲這不是應用程序中應該有任何排序的一個點。另外,我應該注意到,這看起來像我期望的那樣在Linux上工作。但是,它在Windows 7上失敗了。誰能告訴我我做錯了什麼?非常感謝!

回答

3

你不能沒有增加超時做到這一點。這與PHP的實現毫無關係 - 它正是TCP套接字連接應該如何工作的。

由於TCP使用確認(ACK),以保證數據包傳送和排序,當您啓動客戶端發送一個SYN數據包TCP連接,並等待返回SYN/ACK包。客戶端將繼續等待這一點無論直至接收到返回數據包,或客戶決定它等待足夠長的時間,並給出了 - 這是超時的論點,即fsockopen()接受。

當您運行netstat的,它着眼於結合在TCP堆棧上本地機器應用程序 - 這意味着它能夠確定一個端口是否正在使用沒有嘗試連接到它。因此,它可以立即報告套接字是否在使用中。

現實在這裏你有兩個選擇。

  • 供應超時。請記住,超時參數可以是一個浮點數(因此可以少於1秒),所以如果您正在檢查本地計算機,則可以將其設置得非常低。就在測試它在我的Windows XP機器上玩,我發現我可以將其設置爲0.001(1毫秒),併成功地連接到正在運行的服務,並綁定端口返回FALSE。這個1ms超時也適用於我的(當然相對安靜和全千兆)局域網上的其他機器。 YMMV,但在高速網絡中5ms(0.005)應該足夠綽綽有餘。
    例如,此行很好地工作對我來說,並會導致腳本等待1毫秒的最大
define('TEST_SELENIUM', (bool) @fsockopen('localhost', 4444, $en, $es, 0.001)); 
  • shell_exec('netstat');和解析輸出。這肯定只在你檢查本地機器時才起作用,並且可能不會比1ms超時方法更快。它也不是十分便攜的,如在各種操作系統的netstat工具可能會產生非常輕微不同的輸出 - 不同的列排序,不同的分隔的字符,等等等等

還值得一提的是,如果TCP棧配置主動拒絕發送到未綁定端口的數據包(通過返回RST數據包),則fsockopen()將立即失敗。這可能就是爲什麼你說this appears to work the way I would expect it should on Linux - 你測試過的Linux實例是這樣配置的。可能有一些註冊表設置可以讓你配置Windows以這種方式運行,儘管我不知道它是什麼--的傢伙可以幫助你。

+0

謝謝你的非常詳細的答案。該程序將主要在Linux上運行,所以我可能會嘗試您提到的註冊表設置更改可能會發生。這真的是我正在尋找的解決方案。但如果需要,我會確保使用適當的超時。 – golmschenk 2012-08-23 16:01:26