2013-03-18 8 views
5

SSEを使用してクライアントに新しいデータをプッシュし、Flot(javascript charting library)の "live"アップデートを表示することを考えています。私のサーバーは、Pythonのフラスコフレームワーク上で動作し、私はクライアントにデータをプッシュする方法を考え出してきたが、問題は、すぐに私がページを離れると発生します。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

あなたがにAjax呼び出しを行うためにonBeforeUnloadやjQueryのwindow.unload()のいずれかを使用することができますハンドルを閉じる方法がいくつかあります。ような何か:

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

ありunload()/onBeforeUnload()の処理方法といくつかの矛盾があるので、あなたは、クロームのようなもので行うにはいくつかのより多くの仕事を持っていることがあります。

+0

これは私が最終的に来た解決策でした。あなたの答えに感謝します。 – NindzAI

+0

これは私の意見では悪い解決策です。ブラウザが実行しないとメモリリークが発生する可能性があります(予期せずクラッシュする、接続が切断されるなど)。 –

+0

私は「あなたはChromeのようなものでもっとやるべきことがいくつかあるかもしれない」と指摘しています(これは開発者がこれらの種のイベントを発生させるかもしれません...) – bbenne10

2

私は良い答えはありませんが、私は上記のサーバーへのajaxリクエストは良いとは思いません。

フラスコでは、SSEはResponseオブジェクトのストリーミングを使用します.Socketイベントでは、ソケットイベントを処理して割り当てられた他のリソースを解放する方が良いでしょう。

+0

Ajaxメソッドを起動することは理想的ではありませんが、ストリーミングを使用して壊れたパイプを検出することは、ページの終了時に何かを起動するだけのように思えます。特に応答が必要ない場合(私の方法はとにかく失敗するでしょう - 少なくともChromeは応答を提示できないからです) – bbenne10

1

汚れている(モアキーパッチが含まれていますが)解決策が見つかりました。

exceptionは、接続が低下した場合、我々は例外をキャッチし、私たちが好きなようにそれを処理することにパッチを適用することができますSocketServer.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') 

、これは非常に汚いソリューションであり、propablyあなたは組み込みWSGIが仕える使用していない場合は動作しません。 r。

関連する問題