Tôi đang cố tạo một máy chủ Flask để truyền dữ liệu đến máy khách bằng sse. Các đoạn mã thử nghiệm dưới đây dường như làm các trick, nhưng tôi stumbled khi một vấn đề liên quan đến xử lý khách hàng ngắt kết nối.Flask sse-stream không kết thúc sau khi ngắt kết nối firefox
Khi sử dụng Firefox làm ứng dụng khách (phiên bản 28 hoặc 29), dữ liệu sẽ bắt đầu phát trực tuyến như mong đợi. Tuy nhiên, khi tôi tải lại trang, luồng mới sẽ được mở (như mong đợi) nhưng luồng cũ vẫn còn. Chuỗi eventgen() xử lý luồng không bao giờ bị chấm dứt. Trên các ứng dụng khách khác (tôi đã thử IE bằng cách sử dụng triển khai Sự kiện Polyfill EventSource của Yaffle cũng như Chrome), tải lại hoặc đóng kết quả trang trong ngắt kết nối của khách hàng, dẫn đến lỗi ổ cắm phía máy chủ 10053 (máy khách bị ngắt kết nối khỏi máy chủ). Điều này chấm dứt vòng lặp và chỉ giữ cho các luồng đang hoạt động còn sống, đó là hành vi mong đợi.
Sử dụng Process Explorer, tôi nhận thấy kết nối TCP ở phía máy khách (Firefox) bị treo trong trạng thái FIN_WAIT2, trong khi kết nối ở phía máy chủ bị treo trong trạng thái CLOSE_WAIT. Điều kỳ lạ là trên 1 trong số 3 máy (tất cả Win 7 x64) chạy Firefox tôi đã thử nghiệm điều này, ngắt kết nối đã được xử lý một cách chính xác. Chạy trên Python 2.6.5 và 2.7.6 tạo ra kết quả tương tự.
Tôi cũng đã thử thay thế máy chủ Flask tích hợp bằng WSGIserver dựa trên greenlet, nhưng điều này dẫn đến chính xác hành vi tương tự. Hơn nữa, một số dạng luồng/sự kiện nên được sử dụng vì nếu không chạy vòng lặp eventgen() sẽ chặn máy chủ.
Mã thử nghiệm bên dưới phục vụ trang được xác định trong make_html() khi duyệt đến máy chủ cục bộ: 5000 và mở luồng đến/luồng. Luồng hiển thị các hình thức massage có dạng {"content": 0,5556278827744346, "local_id": 4, "msg": 6}, trong đó local_id là id của luồng được mở và msg là số của thông báo hiện tại trong luồng này.
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)
Dường như tôi đã tìm thấy nguồn gốc của vấn đề này. Vấn đề có vẻ là với máy quét liên kết AVG và lá chắn firefox. Vô hiệu hóa lá chắn lướt sóng dường như để giải quyết vấn đề. Máy tính mà nó đã hoạt động đang chạy Avast thay cho AVG. Tôi đoán đây là một lỗi trong AVG, có lẽ nên được sửa. – mojoritty
Giá trị thêm như là một câu trả lời đầy đủ - cảm ơn vì đã mang lại câu trả lời! –