来自http流的非阻塞读取/记录

时间:2009-10-12 21:59:40

标签: python http logging urllib2

我有一个客户端连接到HTTP流并记录它消耗的文本数据。

我向流服务器发送HTTP GET请求...服务器回复并不断发布数据......它将发布文本或定期发送ping(文本)消息......并且永远不会关闭连接。 / p>

我需要以非阻塞的方式读取和记录它消耗的数据。

我正在做这样的事情:

import urllib2

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

我的问题是:
当流连续时,这会阻塞吗? 每个块中读取了多少数据,是否可以指定/调整? 这是读取/记录http流的最佳方式吗?

4 个答案:

答案 0 :(得分:6)

嘿,这是一个三个问题! ; - )

有时可能会阻止 - 即使您的服务器生成数据的速度非常快,理论上网络瓶颈也会导致您的读取被阻止。

使用“for dat in req”读取URL数据意味着一次读取一行 - 如果您正在读取二进制数据(如图像),则不是很有用。如果使用

,您可以获得更好的控制权
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 :(得分:3)

您使用过高级别的界面来很好地控制阻塞和缓冲块大小等问题。如果你不愿意一直走到异步接口(在这种情况下,twisted,已经建议,很难被击败!),为什么不httplib,这毕竟是标准图书馆?与.read(amount)返回的对象上的类似方法相比,HTTPResponse实例amount方法更有可能阻止读取urlopen字节所需的时间(尽管不存在文档规范)在任何一个模块上,嗯...)。

答案 2 :(得分: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()有一些好处,如果Web服务器重定向,您需要基于URL的基本身份验证等。您可以使用select模块,它将告诉您何时有数据要读取。

答案 3 :(得分:1)

是的,当你赶上服务器时它会阻塞,直到服务器产生更多的数据

每个数据都是一行,包括最后的换行符

twisted是一个不错的选择

我会在你的例子中交换with和for around,你真的想打开并关闭到达每一行的文件吗?

相关问题