我有一个客户端连接到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流的最佳方式吗?
答案 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,你真的想打开并关闭到达每一行的文件吗?