2009-10-12 1 views
6

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

Я отправляю потоковый сервер HTTP GET-запрос ... Сервер отвечает и постоянно публикует данные ... Он будет либо публиковать текст, либо отправлять сообщение ping (text) регулярно ... и никогда не будет закрывать соединение.

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

Я делаю что-то вроде этого:

import urllib2 

req = urllib2.urlopen(url)  
for dat in req: 
    with open('out.txt', 'a') as f:   
     f.write(dat) 

Мои вопросы:
будет это когда-либо блокировать, когда поток непрерывен?
Сколько данных считывается в каждом фрагменте и может ли оно быть указано/настроено?
Это лучший способ читать/записывать поток HTTP?

ответ

3

Вы используете слишком высокоуровневый интерфейс, чтобы иметь хороший контроль над такими проблемами, как блокировка и размер блока буферизации. Если вы не согласны полностью перейти к асинхронному интерфейсу (в этом случае twisted, уже предложенный, трудно превзойти!), Почему бы не httplib, который ведь в стандартной библиотеке? Пример HTTPResponse .read(amount), скорее всего, будет блокироваться не более, чем необходимо для чтения amount байт, чем аналогичный метод для объекта, возвращаемого urlopen (хотя, по общему признанию, нет никаких документальных характеристик об этом на любом модуле, hmmm ...).

6

Эй, это три вопроса в одном! ;-)

Иногда это может блокировать - даже если ваш сервер генерирует данные довольно быстро, сетевые узкие места могут теоретически вызывать блокировку ваших чтений.

Чтение данных URL с использованием «для dat in req» означает чтение строки за раз - не очень полезно, если вы читаете двоичные данные, такие как изображение. Вы получите лучший контроль, если используете

chunk = req.read(size) 

который может конечно блок.

Независимо от того, насколько наилучшим образом зависит от специфики, недоступной в вашем вопросе. Например, если вам нужно запускать без каких-либо блокирующих вызовов, вам нужно будет рассмотреть фреймворк вроде Twisted. Если вы не хотите блокировать, чтобы удерживать вас и не хотите использовать Twisted (что представляет собой совершенно новую парадигму по сравнению с блокирующим способом выполнения вещей), тогда вы можете развернуть поток, чтобы читать и писать файл, в то время как ваш основной поток идет своим веселым способом:

def func(req): 
    #code the read from URL stream and write to file here 

... 

t = threading.Thread(target=func) 
t.start() # will execute func in a separate thread 
... 
t.join() # will wait for spawned thread to die 

Очевидно, что я пропущенный ошибки проверки/обработки исключений и т.д., но мы надеемся, что это достаточно, чтобы дать вам картину.

1

Да, когда вы ловите с сервера он будет блокировать, пока сервер не производит больше данных

Каждый Дат будет одна строка, включая символ новой строки в конце

скрученных хороший вариант

Я бы поменял место и в вашем примере, действительно ли вы хотите открыть и закрыть файл для каждой строки?

+0

для/с заказом был намеренно. это откроет/закроет дескриптор файла с каждой записью. Неэффективен для загруженного потока, но в моем случае поток в основном блокируется/ждет, а затем иногда получает данные для регистрации. –

3

Другой вариант - использовать модуль socket напрямую. Установите соединение, отправьте HTTP-запрос, установите сокет в неблокирующий режим, а затем прочитайте данные с помощью socket.recv() обработки исключений «Ресурс временно недоступных» (что означает, что читать нечего). Очень грубый пример заключается в следующем:

import socket, time 

BUFSIZE = 1024 

s = socket.socket() 
s.connect(('localhost', 1234)) 
s.send('GET /path HTTP/1.0\n\n') 
s.setblocking(False) 

running = True 

while running: 
    try: 
     print "Attempting to read from socket..." 
     while True: 
      data = s.recv(BUFSIZE) 
      if len(data) == 0:  # remote end closed 
       print "Remote end closed" 
       running = False 
       break 
      print "Received %d bytes: %r" % (len(data), data) 
    except socket.error, e: 
     if e[0] != 11:  # Resource temporarily unavailable 
      print e 
      raise 

    # perform other program tasks 
    print "Sleeping..." 
    time.sleep(1) 

Однако urllib.urlopen() имеет некоторые преимущества, если веб-сервер перенаправляет, вам нужно URL на основе базовой аутентификации и т.д. Вы можете воспользоваться select модуль, который сообщит вам, когда есть данные читать.

Смежные вопросы