2013-03-18 37 views
5

我正在考慮使用SSE將新數據推送到客戶端,並使用Flot(javascript圖表庫)顯示「實時」更新。我的服務器上的蟒蛇瓶的框架中運行,我已經找到了如何將數據推送到客戶端,但只要我離開這個頁面出現問題:Flask服務器發送事件套接字異常

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()進行調用Ajax一些關閉手柄的拆卸方法。喜歡的東西:

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

有一些不一致的地方與unload()/onBeforeUnload()是如何處理的,所以你可能有一些更多的工作在類似鍍鉻的事情。

+0

這是我最終達成的解決方案,謝謝你的回答。 – NindzAI 2013-05-29 00:52:51

+0

在我看來,這是一個糟糕的解決方案。如果瀏覽器不執行它可能導致內存泄漏(意外崩潰,連接斷開等)。 – 2014-07-26 11:24:53

+0

這就是爲什麼我注意到「你可能需要做更多的工作來處理像Chrome這樣的事情(這可能會也可能不會讓開發者觸發這類事件......) – bbenne10 2014-07-28 16:47:55

2

我沒有更好的答案,但我不認爲上述ajax請求服務器是好的。

在燒瓶中,SSE在Response對象中使用流式傳輸,如果有辦法檢測Response中的斷開連接或管道損壞事件,那將更好地處理套接字事件並釋放分配的其他資源。

+0

雖然你說的正確的方法是啓動ajax方法並不理想,但是使用流式處理然後檢測斷開的管道似乎有很多開銷,只是爲了在頁面關閉時觸發某些內容,特別是如果你不需要響應(這會導致我的方法失敗 - 因爲至少Chrome不允許呈現響應) – bbenne10 2014-01-17 18:26:48

1

我發現一個髒(包括mokey修補),但工作的解決方案。

,因爲有一個exceptionSocketServer.StreamRequestHandler.finish當連接中斷,我們可以修補它捕獲異常,並處理它,因爲我們喜歡:另外

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

再次,這是一個非常骯髒的解決方案,如果你不使用內置的WSGI服務propably將無法正常工作河

相關問題