9

我使用 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()
4

2 回答 2

10

使用time.sleep()可以防止扭曲完成其工作。要使其无法使用time.sleep(),您必须将控制权返回给 twisted。修改现有代码的最简单方法是使用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,我想它正确回答了你的问题。

于 2009-04-29T14:30:35.980 回答
1

原因似乎在扭曲的常见问题解答中进行了解释。在反应器线程可以自由运行之前,扭曲的服务器实际上不会向下划线连接写入任何内容,在这种情况下是在您的方法结束时。但是,您可以在每次睡眠之前使用reactor.doSelect(timeout)以使反应器将其写入连接的内容。

于 2009-04-29T00:41:01.403 回答