2013-03-18 5 views
5

भेजा है, मैं क्लाइंट को नया डेटा धक्का देने और फ़्लोट (जावास्क्रिप्ट चार्टिंग लाइब्रेरी) का उपयोग करके "लाइव" अपडेट प्रदर्शित करने के लिए एसएसई का उपयोग करने के बारे में सोच रहा हूं। मेरे सर्वर अजगर बोतल ढांचे पर चलता है और मैं पता लगा है ग्राहक के लिए डेटा पुश करने के लिए कैसे, लेकिन समस्या यह रूप में जल्द ही मैं पृष्ठ को छोड़ के रूप में होती है:फ्लास्क सर्वर ने ईवेंट सॉकेट अपवाद

Exception happened during processing of request from ('127.0.0.1', 38814) 
Traceback (most recent call last): 
    File "/usr/lib/python2.7/SocketServer.py", line 582, in process_request_thread 
    self.finish_request(request, client_address) 
    File "/usr/lib/python2.7/SocketServer.py", line 323, in finish_request 
    self.RequestHandlerClass(request, client_address, self) 
    File "/usr/lib/python2.7/SocketServer.py", line 640, in __init__ 
    self.finish() 
    File "/usr/lib/python2.7/SocketServer.py", line 693, in finish 
    self.wfile.flush() 
    File "/usr/lib/python2.7/socket.py", line 303, in flush 
    self._sock.sendall(view[write_offset:write_offset+buffer_size]) 
error: [Errno 32] Broken pipe 

मुझे समझ में क्यों त्रुटि तब होती है - सॉकेट है "लाइव" डेटा की सेवा करने वाले अनंत लूप के कारण कभी बंद नहीं हुआ। प्रश्न यह है कि मैं पृष्ठ परिवर्तन का पता कैसे लगा सकता हूं और सॉकेट को साफ रूप से बंद कर सकता हूं? क्या मैं क्लाइंट साइड पर कनेक्शन बंद कर सकता हूं? मैं पृष्ठ परिवर्तन का पता कैसे लगा सकता हूं?

इस सर्वर कोड कंकाल है, मैं निश्चित रूप से प्रदर्शित करने के लिए वस्तुओं की सूची से युक्त json के साथ पाठ संदेश की जगह लेंगे:

def event_stream(): 
    import time 
    while True: 
     time.sleep(1) 
     yield "data: This is a message number X.\n\n" 

@app.route('/stream') 
def stream(): 
    return Response(event_stream(), mimetype="text/event-stream") 

उत्तर

1

आप इस्तेमाल कर सकते हैं या तो onBeforeUnload या jQuery के window.unload() को एक अजाक्स कॉल करने के लिए हैंडल बंद करने वाली कुछ आंसू विधि। की तरह कुछ:

$(window).unload(
    function() { 
     $.ajax(type: 'POST', 
       async: false, 
       url: 'foo.com/client_teardown') 
    } 
} 

unload()/onBeforeUnload() कैसे नियंत्रित किया जाता है के साथ कुछ विसंगतियां हैं, तो आप क्रोम की तरह कुछ में करने के लिए कुछ और काम हो सकता है।

+0

यह वह समाधान था जो मैं अंत में आया था, आपके उत्तर के लिए धन्यवाद। – NindzAI

+0

यह मेरी राय में एक बुरा समाधान है। यदि ब्राउज़र इसे निष्पादित नहीं करता है तो यह स्मृति रिसाव का कारण बन सकता है (अप्रत्याशित रूप से क्रैश हो रहा है, कनेक्शन नीचे चला जाता है आदि)। –

+0

यही कारण है कि मैंने नोट किया "आपके पास क्रोम जैसे कुछ करने के लिए कुछ और काम हो सकता है" (जो डेवलपर को इस तरह की घटनाओं को आग लगने की इजाजत नहीं दे सकता है ...) – bbenne10

2

मेरे पास कोई बेहतर जवाब नहीं है, लेकिन मुझे नहीं लगता कि सर्वर पर उपरोक्त AJAX अनुरोध अच्छा है।

फ्लास्क में, एसएसई प्रतिक्रिया प्रतिक्रिया में स्ट्रीमिंग का उपयोग करता है, अगर प्रतिक्रिया में डिस्कनेक्ट या पाइप टूटा हुआ ईवेंट का पता लगाने का कोई तरीका है, तो सॉकेट ईवेंट को संभालने और अन्य संसाधनों को आवंटित करने के लिए बेहतर होगा।

+0

जबकि आप सही हैं कि एजेक्स विधि को फायर करना आदर्श नहीं है, कुछ स्ट्रीमिंग का उपयोग करना है और फिर टूटी हुई पाइप का पता लगाना बहुत अधिक ओवरहेड की तरह लगता है कि पेज पर कुछ आग लगाना है, खासकर यदि आपको प्रतिक्रिया की आवश्यकता नहीं है (जिससे मेरी विधि किसी भी तरह विफल हो जाएगी - क्योंकि कम से कम क्रोम प्रतिक्रिया प्रस्तुत करने की अनुमति नहीं देता है) – bbenne10

1

मुझे एक गंदा मिला (इसमें मोकी पैचिंग भी शामिल है), लेकिन कामकाजी समाधान।

क्योंकि वहाँ है SocketServer.StreamRequestHandler.finish में एक exception जब कनेक्शन चला जाता है, हम इसे पैच अपवाद को पकड़ने और इसे संभाल कर सकते हैं के रूप में हम चाहते: अतिरिक्त

import socket 
import SocketServer 

def patched_finish(self): 
    try: 
     if not self.wfile.closed: 
      self.wfile.flush() 
      self.wfile.close() 
    except socket.error: 
     # Remove this code, if you don't need access to the Request object 
     if _request_ctx_stack.top is not None: 
      request = _request_ctx_stack.top.request 
      # More cleanup code... 
    self.rfile.close() 

SocketServer.StreamRequestHandler.finish = patched_finish 

आप इसी Request वस्तु का उपयोग करने की जरूरत है, तो आप flask.stream_with_context के साथ घटना धारा रैप करने के लिए, मेरे मामले में की जरूरत है:

@app.route(url) 
def method(host): 
    return Response(stream_with_context(event_stream()), 
        mimetype='text/event-stream') 

फिर, यह एक बहुत ही गंदा समाधान है और अगर आप builtin WSGI का उपयोग नहीं करते की सेवा propably काम नहीं करेगा आर।

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