Próbuję utworzyć serwer Flask, który przesyła dane do klienta za pomocą programu sse. Fragment kodu testowego poniżej wydaje się być skuteczny, ale natknąłem się na problem związany z obsługą rozłączeń klientów.Flas sse-stream nie zakończył się po odłączeniu firefoxa
Podczas korzystania z przeglądarki Firefox jako klienta (wersje 28 lub 29) dane rozpoczynają przesyłanie strumieniowe zgodnie z oczekiwaniami. Jednak po ponownym załadowaniu strony nowy strumień jest otwierany (zgodnie z oczekiwaniami), ale stary strumień nadal pozostaje. Wątek eventgen() obsługujący strumień nigdy nie jest kończony. Na innych klientach (próbowałem używać IE przy użyciu implementacji Polifill EventSource firmy Yaffle oraz Chrome), ponowne załadowanie lub zamknięcie strony skutkuje rozłączeniem klienta, co powoduje błąd po stronie serwera 10053 (klient odłączony od hosta). To kończy pętlę i utrzymuje tylko aktywne strumienie, co jest oczekiwanym zachowaniem.
Korzystając z Process Explorer, zauważyłem, że połączenie TCP po stronie klienta (Firefox) wisi w stanie FIN_WAIT2, podczas gdy połączenie po stronie serwera zawiesza się w stanie CLOSE_WAIT. Dziwne jest to, że na 1 z 3 komputerów (wszystkie Win 7 x64) z Firefoksem, na którym to testowałem, rozłączenia były obsługiwane poprawnie. Uruchomienie w Pythonie 2.6.5 i 2.7.6 dało takie same wyniki.
Próbowałem również zastąpienie wbudowanego serwera Flask za pomocą WSGIserver opartego na zieleni, ale powoduje to dokładnie to samo zachowanie. Ponadto należy użyć jakiejś formy wątków/zdarzeń, ponieważ w przeciwnym razie uruchomienie pętli eventgen() blokuje serwer.
Poniższy kod testowy podaje stronę zdefiniowaną w make_html() podczas przeglądania do localhost: 5000 i otwiera strumień do/stream. Strumień pokazuje masa formularza {"content": 0.5556278827744346, "local_id": 4, "msg": 6}, gdzie local_id to id otwartego strumienia, a msg to numer aktualnej wiadomości w tym strumieniu.
import time, random
import flask
from flask import Flask, json
def make_html():
return """
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script type=text/javascript>
var source = new EventSource('/stream');
source.onmessage = function (event) {
var data = event.data;
var logdiv = $('#log');
logdiv.empty();
logdiv.append('<div class="event">' + data + '</div>');
};
</script>
<h1>Log</h1>
<div id=log>Log ...</div>
<hr />
"""
# ---- Flask app ----
app = Flask(__name__)
@app.route('/')
def index():
return make_html()
counter = 0
def eventgen():
global counter
counter += 1
local_id = counter
msg_count = 0
while True:
msg_count += 1
data = {'msg': msg_count, 'content': random.random(), 'local_id': local_id}
data = json.dumps(data)
yield 'data: ' + data + '\n\n'
print local_id, ':', data
time.sleep(0.5)
@app.route('/stream')
def eventstream():
return flask.Response(eventgen(), mimetype="text/event-stream")
if __name__ == '__main__':
app.run(threaded=True)
Wygląda na to, że znalazłem źródło tego problemu. Problem wydaje się być związany ze skanerem łącza ekranowania AVG i firefox. Wyłączenie osłony przed surfowaniem wydaje się rozwiązać problem. Komputer, na którym już działał, działał z Avast zamiast z AVG. Zgaduję, że to błąd w systemie AVG, który prawdopodobnie powinien zostać naprawiony. – mojoritty
Warto dodać jako pełną odpowiedź - dziękuję za zwrot odpowiedzi! –