Flask sse-stream在Firefox断开连接后未终止。

10

我正在尝试创建一个使用sse向客户端流传数据的Flask服务器。下面的测试代码似乎可以做到这一点,但是我遇到了一个与处理客户端断开相关的问题。

当将Firefox作为客户端(版本28或29)时,数据开始按预期进行流传。但是,当我重新加载页面时,会打开新的流(如预期),但旧流仍然存在。处理流的eventgen()线程将永远不会终止。在其他客户端(我还尝试过使用Yaffle的Polyfill EventSource实现的IE以及Chrome),重新加载或关闭页面会导致客户端断开连接,从而导致服务器端套接字错误10053(客户机从主机断开连接)。这将终止循环并仅保持活动流保持活性,这是预期的行为。

使用Process Explorer,我注意到客户端(Firefox)上的TCP连接处于FIN_WAIT2状态,而服务器端的连接处于CLOSE_WAIT状态。奇怪的是,在我测试此功能的3台计算机中有1台(所有计算机均运行Win 7 x64)正确处理了断开连接。Python 2.6.5和2.7.6的运行结果相同。

我还尝试使用基于greenlet的gevent WSGIserver替换内置的Flask服务器,但结果完全相同。此外,必须使用某种形式的线程/事件集,因为否则运行eventgen()循环将阻塞服务器。

下面的测试代码在浏览localhost:5000时提供定义在make_html()中的页面,并打开到流/stream的连接。流显示{"content": 0.5556278827744346, "local_id": 4, "msg": 6}格式的消息,其中local_id是打开的流的ID,msg是此流中当前消息的数量。

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)

4
我似乎找到了这个问题的源头。问题似乎出在 AVG 的 surf-shield 链接扫描器与 Firefox 不兼容。禁用 surf-shield 似乎可以解决问题。那台已经正常工作的 PC 使用的是 Avast,而不是 AVG。我猜测这是 AVG 的一个 bug,可能需要修复。 - mojoritty
值得作为完整答案添加 - 感谢您将答案带回来! - Sean Vieira
1个回答

4
我似乎找到了这个问题的源头。问题似乎与AVG surf-shield链接扫描仪和Firefox有关。禁用surf-shield似乎可以解决问题。已经解决的电脑上使用的是Avast而不是AVG。我猜测这是AVG中的一个错误,应该被修复。

1
你真的确定这是一个合理的解决方案吗?看起来你只是在客户端上修复了问题,但却对服务器造成了伤害。而且另一个有同样问题的客户端将再次导致服务器出现问题,你无法防范配置错误甚至恶意客户端所带来的影响。 - allo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接