2015-04-06 77 views
3

對於我的項目,我必須檢查網站的狀態(在共享主機上)。'請求'python庫的DNS超時

我使用Python請求庫。

def getStatusCode(url): 
    try: 
     return requests.head(url,timeout=0.3).status_code 
    except: 
     return -1 

此代碼在MacOS 10.10中使用Python3.4以及類似http://www.google.com的網址很有效。如果我拔掉ISP電纜,我立即發現異常。

在Ubuntu服務器14.04與Python3.4,如果我拔掉我的ISP電纜,我永遠不會出現超時錯誤。 Raspbian的同樣問題。

經過一些測試,如果我用IP http://216.58.212.100替換url,Ubuntu服務器會引發一個異常,但由於我在共享的虛擬主機上,所以我無法使用IP。

經過一番研究後,我發現請求庫中的超時和DNS不是由它執行而是由操作系統執行的查找是有區別的。

所以我的問題是什麼是解決這個最美麗的方式?我是否需要添加額外的超時異常在Python這樣的:Timeout on a function call

謝謝

+0

看起來像你回答自己的問題(這是鼓勵在SO)。我不知道更「美麗」的解決方案。我會發布你的最終代碼,並鏈接到任何有關超時操作系統超時的相關研究(這對其他讀者來說很有用)。 – Charlie 2015-04-06 13:39:30

+0

謝謝查理。像我發佈的鏈接或[這裏](http://stackoverflow.com/questions/2281850/timeout-function-if-it-takes-too-long-to-finish)的解決方案的問題是,他們有一個解決方案最少一秒,我跳了一毫秒的分辨率。也許有可能僞造基於IP的請求並編輯頭部tu避免共享主機的問題。如果沒有更好的解決方案,我會發布我的解決方案:) – Kantium 2015-04-06 14:07:24

+0

現在我很好奇 - 爲什麼需要毫秒的URL請求解析?如果您需要並行處理數千個請求,則需要執行一些工作。例如見[這裏](http://stackoverflow.com/questions/14245989/python-requests-non-blocking)。 – Charlie 2015-04-06 14:29:12

回答

0

現在,我有一個更好的瞭解你的問題 - 我想有一個更好的辦法是使用哪個不該」您的操作系統的ping應用在Python中很難做到 - for example。你也應該平均需要1000個請求,並查看平均值,標準偏差,離羣值等。原因是如果一個請求需要500ms,並且你想要1ms的分辨率,那麼你需要產生至少500個請求來獲得任何東西接近你想要的分辨率。

使用Pythons urllib(2)的問題是,它不會像系統級調用那樣執行得差不多,所以你將難以產生足夠的線程來獲得你想要的時間分辨率。

最後,我會再次檢查您的結果商業產品,以確保您的結果是相似的。例如(無從屬關係): http://www.thinkbroadband.com/ping

1

基於查理的鼓勵下,我在這裏發佈我的兩個解決方案

對於我的請求頭添加主機中的第一個,所以我可以將IP地址作爲url並避免DNS查找。

def getStatusCode(url): 
    headers = {'host': 'www.example.com'} 
    try: 
     return requests.head(url,timeout=0.3,headers=headers).status_code 
    except: 
     return -1 

print(getStatusCode('http://1.2.3.4')) 

第二種解決方案是基於信號的使用,但分辨率爲1秒。

class timeout: 
    def __init__(self, seconds=1, error_message='Timeout'): 
     self.seconds = seconds 
     self.error_message = error_message 
    def handle_timeout(self, signum, frame): 
     raise TimeoutError(self.error_message) 
    def __enter__(self): 
     signal.signal(signal.SIGALRM, self.handle_timeout) 
     signal.alarm(self.seconds) 
    def __exit__(self, type, value, traceback): 
     signal.alarm(0) 

def getStatusCode(url): 
    try: 
     return requests.head(url,timeout=0.3).status_code 
    except: 
     return -1 

with timeout(seconds=1): 
    print(getStatusCode('http://www.example.com')) 

(此解決方案是從托馬斯AHLE在https://stackoverflow.com/a/22348885/3896729