asyncore python挂起

时间:2011-12-14 12:31:47

标签: python asyncore

我尝试用asyncore做简单的异步http客户端: 此代码工作正常,输出(快速):

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

ps:我的系统ubuntu 11.10 + python 2.7.2

1 个答案:

答案 0 :(得分:4)

执行self.connect((host, port))时调用阻止名称解析。结合您的本地DNS配置,这就是您的程序在启动时有很长时间延迟的原因。

asyncore的替代方案,并自己想出如何进行非阻塞名称解析,您可能会考虑使用Twisted。 Twisted的TCP连接设置API(主要是reactor.connectTCP或其上构建的API之一)不会阻止。所以天真地使用它将保持适当的异步。