6

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

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

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

我正在做这样的事情:

import urllib2

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

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

4

4 回答 4

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

显然,我省略了错误检查/异常处理等,但希望它足以给你图片。

于 2009-10-12T22:19:36.913 回答
3

您使用的接口太高级,无法很好地控制阻塞和缓冲块大小等问题。如果您不愿意一直使用异步接口(在这种情况下,已经建议过的twisted很难被击败!),为什么不httplib呢?毕竟它在标准库中?HTTPResponse 实例.read(amount)方法更有可能阻塞的时间不超过读取amount字节所需的时间,而不是返回的对象上的类似方法urlopen(尽管在任何一个模块上都没有记录的规范,嗯......)。

于 2009-10-13T03:34:29.790 回答
2

另一种选择是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模块,它会告诉您何时有数据要读取。

于 2009-10-14T06:13:33.390 回答
1

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

每个 dat 将是一行,包括末尾的换行符

扭曲是一个不错的选择

我会在您的示例中交换 with 和 for ,您真的要为到达的每一行打开和关闭文件吗?

于 2009-10-12T22:52:05.600 回答