使用 Twisted 的twisted.web 类,如何刷新我的传出缓冲区?

发布于 2024-07-17 10:33:45 字数 1754 浏览 6 评论 0原文

我使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

病女 2024-07-24 10:33:45

使用time.sleep()可以防止twisted完成它的工作。 为了使它工作,你不能使用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 中有效,我想它正确地回答了你的问题。

Using time.sleep() prevents twisted from doing its job. To make it work you can't use time.sleep(), you must return control to twisted instead. The easiest way to modify your existing code to do that is by using twisted.internet.defer.inlineCallbacks, which is the next best thing since sliced bread:

#!/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()

That works in firefox, I guess it answers your question correctly.

夢归不見 2024-07-24 10:33:45

原因似乎在 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文