2011-12-14 3 views
5

내가 asyncore와 간단한 비동기 HTTP 클라이언트를 수행하려고 응답 : 를이 코드는 잘 작동하고 출력 (빠른 한 정도로)입니다 :asyncore 파이썬은

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 

그러나보다가 내가 호스트가 존재하지와 주석 라인 :

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

실행 나누기, 코드는 데이터의 출력 부, 몇 시간 동안 중단없이 마지막 데이터 출력 응답 :

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 

... 여기에는 일부 호스트가 손실되고 시작시에는 길게 지연됩니다.

왜 이런 일이 발생하고이를 해결할 수 있습니까?

# 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() 

추신 : 내 시스템 우분투 11.10 + 파이썬 2.7.2

+0

우분투가 아닌 내 리눅스 시스템에서 스크립트를 시험해 보았는데, 아무런 문제없이 실행되었습니다. 아마 우분투 설정에 문제가있을 것입니다. – ekhumoro

+0

@ekhumoro : 죄송합니다.이 코드를 사용해도 아무 문제가 없습니다. :) – codersofthedark

답변

4

당신이 self.connect((host, port))을 수행 할 때 당신은 차단 이름 확인을 호출합니다. 로컬 DNS 구성과 결합하여 시작시 프로그램의 지연 시간이 길어집니다.

asyncore의 대안으로 비 차단 이름 확인을 수행하는 방법을 생각할 때 Twisted를 사용하는 것이 좋습니다. Twisted의 TCP 연결 설정 API (주로 reactor.connectTCP 또는 위에 빌드 된 API 중 하나)가 차단되지 않습니다. 그래서 그것의 순진한 사용은 적절하게 비동기로 유지 될 것입니다.