[英]urlopen error 10045, 'address already in use' while downloading in Python 2.5 on Windows
我正在編寫將在Linux,OS X和Windows上運行的代碼。 它從服務器下載大約55,000個文件的列表,然后逐步檢查文件列表,檢查文件是否存在於本地。 (使用SHA哈希驗證和一些其他好東西。)如果文件不在本地存在或哈希不匹配,則下載它們。
服務器端在Ubuntu上通過端口80是普通的Apache 2。
客戶端在Mac和Linux上運行良好,但在下載了大量文件后,在Windows(XP和Vista)上給出了這個錯誤:
urllib2.URLError: <urlopen error <10048, 'Address already in use'>>
這個鏈接: http : //bytes.com/topic/python/answers/530949-client-side-tcp-socket-receiving-address-already-use-upon-connect指向我的TCP端口耗盡,但“netstat -n “從來沒有在”TIME_WAIT“狀態下向我顯示超過六個連接,即使在它出錯之前。
代碼(對於它下載的55,000個文件中的每一個都調用一次)是這樣的:
request = urllib2.Request(file_remote_path)
opener = urllib2.build_opener()
datastream = opener.open(request)
outfileobj = open(temp_file_path, 'wb')
try:
while True:
chunk = datastream.read(CHUNK_SIZE)
if chunk == '':
break
else:
outfileobj.write(chunk)
finally:
outfileobj = outfileobj.close()
datastream.close()
更新:我通過greping日志發現它正好進入下載例程3998次。 我已經多次運行它,每次都失敗了3998。 鑒於鏈接文章指出可用端口是5000-1025 = 3975(有些可能已到期並被重用),它開始看起來更像鏈接文章描述真正的問題。 但是,我仍然不確定如何解決這個問題。 進行注冊表編輯不是一種選擇。
如果它確實是一個資源問題(釋放os套接字資源)
試試這個:
request = urllib2.Request(file_remote_path)
opener = urllib2.build_opener()
retry = 3 # 3 tries
while retry :
try :
datastream = opener.open(request)
except urllib2.URLError, ue:
if ue.reason.find('10048') > -1 :
if retry :
retry -= 1
else :
raise urllib2.URLError("Address already in use / retries exhausted")
else :
retry = 0
if datastream :
retry = 0
outfileobj = open(temp_file_path, 'wb')
try:
while True:
chunk = datastream.read(CHUNK_SIZE)
if chunk == '':
break
else:
outfileobj.write(chunk)
finally:
outfileobj = outfileobj.close()
datastream.close()
如果你想要你可以插入一個睡眠,或者你可以依賴它
在我的win-xp上問題沒有出現(我下載了5000次)
我通過進程黑客觀察我的進程和網絡。
在框外思考,你似乎試圖解決的問題已經被一個名為rsync的程序解決了。 您可能會查找Windows實施,看看它是否滿足您的需求。
您應該認真考慮復制和修改此pyCurl示例,以便有效下載大量文件。
你應該真正使用持久的HTTP連接,而不是為每個請求打開一個新的TCP連接 - 看看urlgrabber (或者只是在keepalive.py上看看如何為urllib2添加keep-alive連接支持)。
所有跡象都表明缺少可用的插座。 你確定只有6個處於TIME_WAIT狀態嗎? 如果您正在運行如此多的下載操作,netstat很可能會超出您的終端緩沖區。 我發現netstat stat在正常使用期間超出了我的終端。
解決方案是修改代碼以重用套接字。 或者引入超時。 跟蹤你有多少個開放插座也沒什么壞處。 優化等待。 Windows XP的默認超時為120秒。 如果你的插座耗盡,你至少要睡這么長時間。 不幸的是,當套接字關閉並離開TIME_WAIT狀態時,看起來很容易從Python檢查。
鑒於請求和超時的異步性質,執行此操作的最佳方法可能是在一個線程中。 使每個威脅在完成之前睡眠2分鍾。 您可以使用信號量或限制活動線程數,以確保不會耗盡套接字。
這是我如何處理它。 您可能希望將異常子句添加到fetch部分的內部try塊,以警告您有關失敗的提取。
import time
import threading
import Queue
# assumes url_queue is a Queue object populated with tuples in the form of(url_to_fetch, temp_file)
# also assumes that TotalUrls is the size of the queue before any threads are started.
class urlfetcher(threading.Thread)
def __init__ (self, queue)
Thread.__init__(self)
self.queue = queue
def run(self)
try: # needed to handle empty exception raised by an empty queue.
file_remote_path, temp_file_path = self.queue.get()
request = urllib2.Request(file_remote_path)
opener = urllib2.build_opener()
datastream = opener.open(request)
outfileobj = open(temp_file_path, 'wb')
try:
while True:
chunk = datastream.read(CHUNK_SIZE)
if chunk == '':
break
else:
outfileobj.write(chunk)
finally:
outfileobj = outfileobj.close()
datastream.close()
time.sleep(120)
self.queue.task_done()
elsewhere:
while url_queue.size() < TotalUrls: # hard limit of available ports.
if threading.active_threads() < 3975: # Hard limit of available ports
t = urlFetcher(url_queue)
t.start()
else:
time.sleep(2)
url_queue.join()
對不起,我的python有點生疏,所以如果我錯過了什么,我不會感到驚訝。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.