2011-12-14 27 views
5

Tôi cố gắng làm đơn giản khách hàng http async với asyncore: Mã này hoạt động tốt và đầu ra là (nhanh enought):asyncore trăn treo

www.gmail.com : recv http code: 301 
www.yandex.ru : recv http code: 200 
www.python.org : recv http code: 200 
www.google.ru : recv http code: 200 
www.gravatar.com : recv http code: 302 
www.com.com : recv http code: 302 
www.yahoo.com : recv http code: 302 
www.bom.com : recv http code: 301 

Nhưng hơn tôi dòng bỏ ghi chú với không tồn tại host:

#c = AsyncHTTP('http://www.no-such-host.ru') #!this line breaks execution! 

các vi phạm thực hiện, mã treo một thời gian, sản lượng một phần của dữ liệu và bị treo không có đầu ra dữ liệu cuối cùng:

connection error: [Errno -5] No address associated with hostname 
www.gmail.com : recv http code: 301 
www.yandex.ru : recv http code: 200 
www.yahoo.com : recv http code: 302 
www.com.com : recv http code: 302 
www.bom.com : recv http code: 301 
www.gravatar.com : recv http code: 302 

... một số máy chủ bị mất ở đây và trì hoãn lâu lúc bắt đầu.

Tại sao điều này xảy ra và cách khắc phục sự cố này?

# coding=utf-8 
import asyncore 
import string, socket 
import StringIO 
import mimetools, urlparse 

class AsyncHTTP(asyncore.dispatcher): 
    # HTTP requestor 

    def __init__(self, uri): 
     asyncore.dispatcher.__init__(self) 

     self.uri = uri 


     # turn the uri into a valid request 
     scheme, host, path, params, query, fragment = urlparse.urlparse(uri) 
     assert scheme == "http", "only supports HTTP requests" 
     try: 
      host, port = string.split(host, ":", 1) 
      port = int(port) 
     except (TypeError, ValueError): 
      port = 80 # default port 
     if not path: 
      path = "/" 
     if params: 
      path = path + ";" + params 
     if query: 
      path = path + "?" + query 

     self.request = "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n" % (path, host) 

     self.host = host 
     self.port = port 

     self.status = None 
     self.header = None 
     self.http_code = None 
     self.data = "" 

     # get things going! 
     self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 
     #self.connect((host, port)) 
     #return 
     try: 
      self.connect((host, port)) 
     except Exception,e: 
      self.close() 
      self.handle_connect_expt(e) 

    def handle_connect(self): 
     self.send(self.request) 

    def handle_expt(self): 
     print "handle_expt error!" 
     self.close() 

    def handle_error(self): 
     print "handle_error error!" 
     self.close() 

    def handle_connect_expt(self,expt): 
     print "connection error:",expt 

    def handle_code(self):   
     print self.host," : ","recv http code: ",self.http_code 


    def handle_read(self): 
     data = self.recv(2048) 
     #print data 
     if not self.header: 
      self.data = self.data + data 
      try: 
       i = string.index(self.data, "\r\n\r\n") 
      except ValueError: 
       return # continue 
      else: 
       # parse header 
       fp = StringIO.StringIO(self.data[:i+4]) 
       # status line is "HTTP/version status message" 
       status = fp.readline() 
       self.status = string.split(status, " ", 2) 
       self.http_code = self.status[1] 
       self.handle_code()  

       # followed by a rfc822-style message header 
       self.header = mimetools.Message(fp) 
       # followed by a newline, and the payload (if any) 
       data = self.data[i+4:] 
       self.data = "" 
       #header recived 
       #self.close() 


    def handle_close(self): 
     self.close() 




c = AsyncHTTP('http://www.python.org') 
c = AsyncHTTP('http://www.yandex.ru') 
c = AsyncHTTP('http://www.google.ru') 
c = AsyncHTTP('http://www.gmail.com') 
c = AsyncHTTP('http://www.gravatar.com') 
c = AsyncHTTP('http://www.yahoo.com') 
c = AsyncHTTP('http://www.com.com') 
c = AsyncHTTP('http://www.bom.com') 
#c = AsyncHTTP('http://www.no-such-host.ru') #!this line breaks execution! 
asyncore.loop() 

ps: Hệ thống của tôi ubuntu 11.10 + python 2.7.2

+0

Đã thử tập lệnh của bạn trên hệ thống Linux của tôi (không phải ubuntu) và nó chạy mà không có bất kỳ vấn đề nào bạn đã báo cáo. Vì vậy, có lẽ phải có một số vấn đề với thiết lập ubuntu của bạn. – ekhumoro

+0

@ekhumoro: Tôi đã nhầm lẫn, thậm chí tôi đã thử mã này và đang làm việc mà không gặp vấn đề gì :) – codersofthedark

Trả lời

4

Bạn có thể gọi một tên có độ phân giải chặn khi bạn làm self.connect((host, port)). Kết hợp với cấu hình DNS cục bộ của bạn, đây là lý do tại sao chương trình của bạn bị trì hoãn lâu khi khởi động.

Một giải pháp thay thế cho asyncore và tìm cách tự giải quyết tên không chặn, bạn có thể nghĩ đến việc sử dụng Twisted. API thiết lập kết nối TCP của Twisted (chủ yếu là reactor.connectTCP hoặc một trong các API được xây dựng trên đầu trang) không chặn. Vì vậy, một sử dụng ngây thơ của nó sẽ vẫn đúng cách không đồng bộ.