2009-04-22 15 views
9

मैंने ट्विस्ट का उपयोग करके एक साधारण http सर्वर बनाया है, जो सामग्री-प्रकार: मल्टीपार्ट/एक्स-मिश्रित-प्रतिस्थापन शीर्षलेख भेजता है। मैं इसका उपयोग एक http क्लाइंट का परीक्षण करने के लिए कर रहा हूं जिसे मैं दीर्घकालिक स्ट्रीम स्वीकार करने के लिए सेट अप करना चाहता हूं।ट्विस्ट के twisted.web कक्षाओं का उपयोग करके, मैं अपने आउटगोइंग बफर कैसे फ़्लश कर सकता हूं?

उत्पन्न हुई समस्या यह है कि मेरा क्लाइंट अनुरोध 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() 

उत्तर

9

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() 

कि फ़ायरफ़ॉक्स में काम करता है, मैं इसे सही ढंग से अपने सवाल का जवाब लगता है।

+0

क्या यह प्रभावी रूप से किसी भी अन्य को अनुमति देता है (जैसा कि रिएक्टर द्वारा चुना जाता है) कोड उत्पन्न होने पर कोड चलाया जाता है? यदि ऐसा है तो आपको बहुत सावधान रहना होगा कि आपके द्वारा उपयोग किए जा रहे डेटा को अन्य कोड द्वारा अधिलेखित या परिवर्तित नहीं किया गया है। नीचे दिए गए यूआरएल पर टिप्पणी देखें जिसे मैंने कहीं भी नहीं देखा है: http://twistedmatrix.com/pipermail/twisted-python/2007- फरवरी/014869.html – Mick

1

कारण FAQ for twisted में समझाया गया प्रतीत होता है। जब तक रिएक्टर थ्रेड चलाने के लिए स्वतंत्र नहीं होता है, तब तक मुड़ता हुआ सर्वर वास्तव में अंडरलाइनिंग कनेक्शन पर कुछ भी नहीं लिखता है, इस मामले में आपकी विधि के अंत में। हालांकि आप reactor.doSelect(timeout) का उपयोग कर सकते हैं इससे पहले कि आप प्रत्येक नींद को रिएक्टर को लिखने के लिए कनेक्शन के साथ क्या लिखें।

+5

आपको कभी भी रिएक्टर को कॉल नहीं करना चाहिए। चयन करें। यह रिएक्टरों में पोर्टेबल नहीं है, और यह फिर से दर्ज करके रिएक्टर को आसानी से तोड़ सकता है जहां इसे फिर से दर्ज करने की उम्मीद नहीं है। –

+2

उपरोक्त टिप्पणी/सुधार के बावजूद उपरोक्त चयन करें, किसी को भी अपने परिवहन कोड के साथ क्या हो रहा है, यह जानने की कोशिश कर रहा है कि एफएक्यू के सूचक को स्पॉट पर विशेष रूप से "ट्विस्ट केवल प्रतिक्रिया भेज सकता है जब आप रिएक्टर को निष्पादन पर नियंत्रण छोड़ देते हैं उदाहरण के लिए, यदि आपके पास एक परिवहन के लिए अनंत लूप लेखन डेटा है, तो डेटा वास्तव में कभी नहीं भेजा जाएगा क्योंकि नियंत्रण कभी भी आपका कोड नहीं छोड़ेगा और रिएक्टर पर वापस आ जाएगा। " – Mick

संबंधित मुद्दे