Как использовать Twisted Twisted.web классы, как очистить мои исходящие буферы?
Я сделал простой http-сервер, используя Twisted, который отправляет заголовок 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()
2 ответа
С помощью time.sleep()
мешает витой делать свою работу. Чтобы заставить его работать, вы не можете использовать time.sleep()
, вместо этого вы должны вернуть управление в витую. Самый простой способ изменить существующий код для этого - использовать twisted.internet.defer.inlineCallbacks
, что является следующей лучшей вещью после нарезанного хлеба:
#!/usr/bin/env python
import time
from twisted.web import http
from twisted.internet import protocol
from twisted.internet import reactor
from twisted.internet import defer
def wait(seconds, result=None):
"""Returns a deferred that will be fired later"""
d = defer.Deferred()
reactor.callLater(seconds, d.callback, result)
return d
class StreamHandler(http.Request):
BOUNDARY = 'BOUNDARY'
def writeBoundary(self):
self.write("--%s\n" % (self.BOUNDARY))
def writeStop(self):
self.write("--%s--\n" % (self.BOUNDARY))
@defer.inlineCallbacks
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()
yield wait(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()
yield wait(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__':
reactor.listenTCP(8800, StreamFactory())
reactor.run()
Это работает в Firefox, я думаю, это правильно отвечает на ваш вопрос.
Причина, кажется, объясняется в FAQ для витой. Витой сервер на самом деле ничего не записывает в подчеркивающее соединение, пока поток реактора не будет запущен, в данном случае в конце вашего метода. Однако вы можете использовать реактор.doSelect(время ожидания) перед каждым сном, чтобы реактор записал, что он имеет для соединения.