来自http流的非阻塞读/日志

2024-05-02 11:31:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个客户端,它连接到一个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流的最佳方式吗?


Tags: 数据文本服务器http消息客户端get方式
3条回答

嘿,三个问题合一!;-)

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

使用“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

很明显,我忽略了错误检查/异常处理等,但希望这足以给您提供图片。

您使用的接口级别太高,无法很好地控制诸如阻塞和缓冲块大小之类的问题。如果您不愿意一直使用异步接口(在这种情况下,twisted,已经建议了,很难打败!),为什么不httplib,毕竟它在标准库中?HTTPResponse实例.read(amount)方法比urlopen返回的对象上的类似方法更可能阻塞不超过读取amount字节所需的时间(尽管不可否认,两个模块上都没有关于该方法的文档说明,hmmm…)。

另一种选择是直接使用socket模块。建立连接,发送HTTP请求,将套接字设置为非阻塞模式,然后使用socket.recv()处理“Resource temporary unavailable”异常读取数据(这意味着没有要读取的内容)。一个非常粗略的例子是:

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模块,它将告诉您何时有数据要读取。

相关问题 更多 >