使用 Twisted 的twisted.web 类,如何刷新我的传出缓冲区?
我使用 Twisted 创建了一个简单的 http 服务器,它发送 Content-Type: multipart/x-mixed-replace 标头。 我正在使用它来测试一个 http 客户端,我想将其设置为接受长期流。
出现的问题是我的客户端请求挂起,直到 http.Request 调用 self.finish(),然后它立即接收所有多部分文档。
有没有办法手动将输出缓冲区刷新到客户端? 我假设这就是我没有收到单独的多部分文档的原因。
#!/usr/bin/env python
import time
from twisted.web import http
from twisted.internet import protocol
class StreamHandler(http.Request):
BOUNDARY = 'BOUNDARY'
def writeBoundary(self):
self.write("--%s\n" % (self.BOUNDARY))
def writeStop(self):
self.write("--%s--\n" % (self.BOUNDARY))
def process(self):
self.setHeader('Connection', 'Keep-Alive')
self.setHeader('Content-Type', "multipart/x-mixed-replace;boundary=%s" % (self.BOUNDARY))
self.writeBoundary()
self.write("Content-Type: text/html\n")
s = "<html>foo</html>\n"
self.write("Content-Length: %s\n\n" % (len(s)))
self.write(s)
self.writeBoundary()
time.sleep(2)
self.write("Content-Type: text/html\n")
s = "<html>bar</html>\n"
self.write("Content-Length: %s\n\n" % (len(s)))
self.write(s)
self.writeBoundary()
time.sleep(2)
self.write("Content-Type: text/html\n")
s = "<html>baz</html>\n"
self.write("Content-Length: %s\n\n" % (len(s)))
self.write(s)
self.writeStop()
self.finish()
class StreamProtocol(http.HTTPChannel):
requestFactory = StreamHandler
class StreamFactory(http.HTTPFactory):
protocol = StreamProtocol
if __name__ == '__main__':
from twisted.internet import reactor
reactor.listenTCP(8800, StreamFactory())
reactor.run()
I've made a simple http server using Twisted, which sends the Content-Type: multipart/x-mixed-replace header. I'm using this to test an http client which I want to set up to accept a long-term stream.
The problem that has arisen is that my client request hangs until the http.Request calls self.finish(), then it receives all multipart documents at once.
Is there a way to manually flush the output buffers down to the client? I'm assuming this is why I'm not receiving the individual multipart documents.
#!/usr/bin/env python
import time
from twisted.web import http
from twisted.internet import protocol
class StreamHandler(http.Request):
BOUNDARY = 'BOUNDARY'
def writeBoundary(self):
self.write("--%s\n" % (self.BOUNDARY))
def writeStop(self):
self.write("--%s--\n" % (self.BOUNDARY))
def process(self):
self.setHeader('Connection', 'Keep-Alive')
self.setHeader('Content-Type', "multipart/x-mixed-replace;boundary=%s" % (self.BOUNDARY))
self.writeBoundary()
self.write("Content-Type: text/html\n")
s = "<html>foo</html>\n"
self.write("Content-Length: %s\n\n" % (len(s)))
self.write(s)
self.writeBoundary()
time.sleep(2)
self.write("Content-Type: text/html\n")
s = "<html>bar</html>\n"
self.write("Content-Length: %s\n\n" % (len(s)))
self.write(s)
self.writeBoundary()
time.sleep(2)
self.write("Content-Type: text/html\n")
s = "<html>baz</html>\n"
self.write("Content-Length: %s\n\n" % (len(s)))
self.write(s)
self.writeStop()
self.finish()
class StreamProtocol(http.HTTPChannel):
requestFactory = StreamHandler
class StreamFactory(http.HTTPFactory):
protocol = StreamProtocol
if __name__ == '__main__':
from twisted.internet import reactor
reactor.listenTCP(8800, StreamFactory())
reactor.run()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用
time.sleep()
可以防止twisted完成它的工作。 为了使它工作,你不能使用time.sleep()
,你必须将控制权返回给twisted。 修改现有代码的最简单方法是使用twisted.internet.defer.inlineCallbacks
,这是继切片面包之后最好的事情:这在 Firefox 中有效,我想它正确地回答了你的问题。
Using
time.sleep()
prevents twisted from doing its job. To make it work you can't usetime.sleep()
, you must return control to twisted instead. The easiest way to modify your existing code to do that is by usingtwisted.internet.defer.inlineCallbacks
, which is the next best thing since sliced bread:That works in firefox, I guess it answers your question correctly.
原因似乎在 twisted 常见问题解答中进行了解释。 在反应器线程可以自由运行之前(在本例中是在方法的末尾),扭曲的服务器实际上不会向下划线连接写入任何内容。 但是,您可以使用 reactor.doSelect(timeout) 在每次睡眠之前让反应器将其所拥有的内容写入连接。
The reason seems to be explained in the FAQ for twisted. The twisted server does not actually write anything to the underlining connection until the reactor thread is free to run, in this case at the end of your method. However you can use reactor.doSelect(timeout) before each of your sleeps to make the reactor write what it has to the connection.