2013-03-18 4 views
5

Я думаю об использовании SSE для ввода новых данных клиенту и использования Flot (javascript charting library) отображения «живых» обновлений. Мой сервер работает на питон рамках Колбы и я понял, как передать данные клиенту, но проблема возникает, как только я оставляю страницу:Флажок-сервер отправил событие сокет-исключение

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() обрабатываются, так что вы можете иметь больше работы, чтобы сделать в чем-то вроде Chrome.

+0

Это было решение, к которому я пришел в конце концов, спасибо за ваш ответ. – NindzAI

+0

Это плохое решение, на мой взгляд. Это может привести к утечке памяти, если браузер не выполнит ее (неожиданно сбой, соединение отключается и т. Д.). –

+0

Вот почему я отметил, что «у вас может быть больше работы, чтобы сделать что-то вроде Chrome» (что может или не позволить разработчику запускать подобные события ...) – bbenne10

2

У меня нет лучшего ответа, но я не думаю, что вышеуказанный запрос ajax на сервер хорош.

В фляге SSE использует потоковое вещание в объекте Response, если есть способ обнаружить разрывное событие disconnect или pipe в Response, что было бы лучше обработать события сокета и освободить выделенные ресурсы.

+0

Хотя вы правы в том, что стрельба по ajax-методу не идеальна, что-то использует потоковое вещание, а затем обнаруживает разбитый трубу, кажется, довольно много накладных расходов, чтобы просто сжечь что-то на странице, особенно если вам не нужен ответ (что приведет к тому, что мой метод будет терпеть неудачу в любом случае - поскольку, по крайней мере, Chrome не позволяет представить ответ) – bbenne10

1

Я нашел грязный (включает исправление mokey), но рабочее решение.

Поскольку есть 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 служить р.

Смежные вопросы