Уведомления

Группа в Telegram: @pythonsu

#1 Дек. 14, 2011 13:24:47

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

asyncore глохнет

Асинхронный http клинет на asyncore
работает нормально но при раскомментировании строки в конце кода с несуществующим хостом
#c = AsyncHTTP('http://www.no-such-host.ru')
код глохнет, виснет и выдает только часть данных, почему так происходит как поправить?


# 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') #!СТРОКА ЛОМАЕТ КОД!
asyncore.loop()



Офлайн

#2 Дек. 14, 2011 17:54:49

dimabest
От:
Зарегистрирован: 2009-02-12
Сообщения: 253
Репутация: +  0  -
Профиль   Отправить e-mail  

asyncore глохнет

Каким образом ломает?

У меня выводит:

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



Офлайн

#3 Дек. 14, 2011 18:43:41

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

asyncore глохнет

У меня выдает часть только сайтов, причем виснет в начале, потом кусок выплевывает и опять зависает уже оч надолго и потом выдает последнюю строку.

---долго висит---
connection error: [Errno -5] No address associated with hostname
www.yandex.ru : recv http code: 200
www.gmail.com : recv http code: 301
www.yahoo.com : recv http code: 302
www.google.ru : recv http code: 200
www.gravatar.com : recv http code: 302
www.com.com : recv http code: 302
www.bom.com : recv http code: 301
---очень доооооолго висит---
handle_error error!
Система ubuntu 11.10 python 2.7.2

У вас судя по выводу т.к
connection error: No address associated with hostname
первая, все остальные ждут пока соединение откинет ошибку? этого тоже бы хотелось избежать, те чтобы оно выдавало последним: connection error: No address associated with hostname , выдав сразу все доступные сайты. Сейчас получается что одно неудачное соединение блокирует всю асинхронность.



Отредактировано (Дек. 14, 2011 19:10:41)

Офлайн

#4 Дек. 14, 2011 23:33:35

dimabest
От:
Зарегистрирован: 2009-02-12
Сообщения: 253
Репутация: +  0  -
Профиль   Отправить e-mail  

asyncore глохнет

У меня тоже ubuntu 11.10 и python 2.7.2. Работает быстро.

Перед коннектом к удаленному серверу, сокет должен преобразовать "http://www.no-such-host.ru" в ip-адрес. Такое преобразование делает функция gethostbyname() из модуля socket, которая посылает запросы в сеть. Вызов блокирующий!

А если в консоли запустить?

>>> from socket import gethostbyname
>>> gethostbyname("http://www.no-such-host.ru")
Должно “очень доооооолго висеть”.



Отредактировано (Дек. 14, 2011 23:33:51)

Офлайн

#5 Дек. 15, 2011 15:14:38

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

asyncore глохнет

да спасибо, проблема в нем.



Офлайн

#6 Дек. 15, 2011 15:58:41

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

asyncore глохнет

Еще такой вопрос, как задать таймаут
например для недоступного сайта

c = AsyncHTTP('http://www.evtur.ru')
висит по 10 минут и более, как задать например таймаут в 5 сек?



Офлайн

#7 Дек. 15, 2011 18:18:36

dimabest
От:
Зарегистрирован: 2009-02-12
Сообщения: 253
Репутация: +  0  -
Профиль   Отправить e-mail  

asyncore глохнет

По поводу gethostbyname()

В libevent столкнулись с такой же проблемой: http://www.wangafu.net/~nickm/libevent-book/Ref9_dns.html
Поэтому написали свои функции, которые посылают неблокирующие DNS запросы.

—————————————

По поводу недоступного сайта - никак.



Офлайн

#8 Дек. 15, 2011 18:32:42

dimabest
От:
Зарегистрирован: 2009-02-12
Сообщения: 253
Репутация: +  0  -
Профиль   Отправить e-mail  

asyncore глохнет

asyncore - слабенький модуль.

Во-первых, нет таймера, а значит нельзя:
1. запускать задачи через n секунд
2. прикрутить к сокетам таймауты

Без этих пунктов вообще никак.

Во-вторых, мягко говоря, неоптимальный алгоритм внутри. Перед каждым системным вызовом poll() или select() циклом пробегать по всем объектам dispatcher и вызывать методы is_writable() и is_readable() это просто ахтунг. Представте 10 тыс. одновременных соединений… это почти 20 тыс. никому не нужных холостых вызовов функций перед одним системным…



Отредактировано (Дек. 15, 2011 18:33:18)

Офлайн

#9 Дек. 15, 2011 20:43:32

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

asyncore глохнет

я для асинхронных днс испоьзовал это http://code.google.com/p/adns-python/
У меня вообще задача шустро асинхроно парсить урлы, что посоветуюте для этого?
уже думаю самому написать напрямую с epoll взамен, или попробвать concurence пока не решил :)

кстати есть еще libev вроде быстрее чем libevent.
http://code.google.com/p/pyev/



Офлайн

#10 Дек. 15, 2011 21:43:00

dimabest
От:
Зарегистрирован: 2009-02-12
Сообщения: 253
Репутация: +  0  -
Профиль   Отправить e-mail  

asyncore глохнет

Не знаю как проще, но в целях самообразования хорошо взять epoll и самому написать.
Вот хорошая статейка http://scotdoyle.com/python-epoll-howto.html

Сам цикл простой, сложности с исключениями: EINPROGRESS, EWOULDBLOCK, EAGAIN, EBADF и т.д. Нужно разобратся на каких ситемных вызовах какие исключения могут возникнуть, какие проглотить, какие обработать, а какие пропустить наверх.

Реализовать таймеры не сложно. Заводим список, например tasks, в который сохраняем unix timestamp (время возникновения события, например таймаут при попытке коннекта к сайту) и callback (функцию, которую нужно вызвать при наступлении события). Перед системным вызовом epoll.poll(timeout) определяем таймаут - либо дефолтный, либо время до ближайшего события из списка tasks, в зависимости от того, что меньше. Наступило ли событие можно определить сравнив unix timestamp из списка tasks с текущим временем.

Вообщем на словах все просто :)



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version