python 如何连续读取一个由服务器发来的非阻塞请求?

2014-11-22 18:39:29 +08:00
 xdf331
假设服务端采用tornado,对一个handler使用@tornado.web.asynchronous装饰器,并在一定时间内就self.flush()。

python的客户端如何连续读取这样的请求?

有人说使用pycurl,但是好像在win下需要别的dll,如何在不使用外部dll的下情况下实现?
使用原生库最好了。
4561 次点击
所在节点    Python
7 条回复
mulog
2014-11-22 20:12:56 +08:00
什么叫客户端连续读取请求。。。?

我想你是说非阻塞地发送请求? tornado不是带了个AsyncHTTPClient么
mhycy
2014-11-22 20:15:24 +08:00
越说越复杂就是没说清事情本质.....
lianghui
2014-11-22 21:37:03 +08:00
如果是tornado4, 可以用chunked transfer enoding传送,那么客户端支持chunk编码就可以做数据接收了。http://en.wikipedia.org/wiki/Chunked_transfer_encoding。

tornado3不支持chunk:




import tornado.ioloop
import tornado.iostream
import socket

```python
class WebRequest(object):

LINE_END = b'\r\n'
def __init__(self, host, port=80, callback=None):
self.host = host
self.port =port
self.headers = {}
self.data = ''
self.callback = callback
self.transfer = 'stream'
self.http_ver_with_status = ''

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
self.stream = tornado.iostream.IOStream(s)
self.stream.connect((self.host, self.port), self.send_request)


def send_request(self):
self.stream.write(b"GET / HTTP/1.0\r\nHost: %s\r\n\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36\r\n" %self.host)
self.stream.read_until(self.LINE_END*2, self.on_headers)

def on_headers(self, data):
for line in data.split(self.LINE_END):
parts = line.split(b":", 1)
if len(parts) == 2:
self.headers[parts[0].strip()] = parts[1].strip()
else:
self.http_ver_with_status = line
if 'Content-Length' in self.headers:
if int(self.headers[b"Content-Length"]) > 0:
print self.headers
print 'content_length: ', self.headers[b"Content-Length"]
self.transfer = 'content_length'
self.stream.read_bytes(int(self.headers[b"Content-Length"]), self.on_body)
else:
self.callback(self)
self.stream.close()

elif self.headers.get(b'Transfer-Encoding') == 'chunked':
print 'chunk'
self.transfer = 'chunked'
self.on_chunk()
else:
self.transfer = 'stream'
callback = lambda data: self.on_stream(data, True)
streaming_callback = lambda data: self.on_stream(data, False)
self.stream.read_until_close(callback, streaming_callback)

def on_body(self, data):
self.data += data
self.callback(self)
self.stream.close()

def on_chunk(self):
self.stream.read_until_regex(self.LINE_END, self.on_chunk_header)

def on_chunk_header(self, data):
length = int(data)
if length > 0:
self.stream.read_bytes(length+len(self.LINE_END), self.on_chunk_data)
else:
self.stream.read_bytes(length+len(self.LINE_END), self.on_chunk_end)


def on_chunk_end(self, data):
self.callback(self)
self.stream.close()


def on_chunk_data(self, data):
print data
self.data += data
self.on_chunk()


def on_stream(self, data, finish=False):
# do some thing
if finish:

self.data += data
self.callback(self)
self.stream.close()
else:
self.data += data


def callback(req):
print req.http_ver_with_status
print "Transfer :" , req.transfer
print "Headers: ", req.headers
print "Data: ", req.data
req = WebRequest('cn.bing.com', 80, on_bing)


def on_bing(req):
print req.http_ver_with_status
print "Transfer :" , req.transfer
print "Headers: ", req.headers
print "Data: ", req.data
tornado.ioloop.IOLoop.instance().stop()

if __name__ == '__main__':
req = WebRequest('www.baidu.com', 80, callback)
tornado.ioloop.IOLoop.instance().start()
```
lianghui
2014-11-22 21:42:35 +08:00
xdf331
2014-11-22 22:48:31 +08:00
@lianghui
问题已经解决,和你的方法差不多,也是使用socket来模仿一个HTTP请求。但是我没有用ttornado.IOstream进行包装,我是直接用socket.recv(),不停的接收内容再处理就行了。
lianghui
2014-11-22 23:05:29 +08:00
@xdf331 复杂的,可能还需要处理follow,以及if-modify-sine等,和断点请求
ryd994
2014-11-23 03:45:25 +08:00
request.read(1)行吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/148537

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX