问题描述
在我的项目中,我使用flask_socketio 作为服务器,使用socket.io-client 作为客户端。我的 main.py(flask 服务器)不断读取不断更新的日志文件(console.log)。当在 UI 中单击开始按钮时,会显示日志文件的数据,但是随着我的日志文件的更新,更新后的数据不会显示在 UI 中。我必须刷新页面或再次单击该按钮才能查看更新的数据。 我希望通过单击按钮在 UI 上实时流式传输日志文件的数据。如何解决这个问题?
烧瓶代码
from flask import Flask,jsonify
# Needed for localhost testing.
from flask_cors import CORS,cross_origin
from flask_socketio import SocketIO,emit
from time import sleep
import pdb
import json
app = Flask(__name__)
# Socket io setup.
app.config['SECRET_KEY'] = 'secret!'
# |cors_allowed_origins| is required for localhost testing.
socket = SocketIO(app,cors_allowed_origins="*")
# For localhost testing.
CORS(app)
@socket.on('event_stream',namespace='/logConsole')
def test_connect():
def generate():
fname = "./src/console.log"
with open(fname) as f:
yield f.read()
emit_data = next(generate())
socket.sleep(0)
emit('custom-server-msg',{'data': emit_data})
if __name__ == '__main__':
socket.run(app)
反应代码
import React from 'react'
import io from 'socket.io-client'
class App extends React.Component {
state = { startvar: true,setvar: false };
setSocketListeners() {
let socket = io.connect('ws://localhost:5000/logConsole');
socket.emit('event_stream',() => {
console.log("Websocket connected: " + socket.connected)
})
socket.on('custom-server-msg',(data) => {
console.log("Data received: " + data.data)
const setup_logs = data.data;
this.setState({ setup_logs });
})
}
render() {
return (
<div className="App">
<h1>Data from log file</h1>
<button type="button" onClick={() => this.setSocketListeners()}>Start</button>
<p>{this.state.setup_logs}</p>
</div>
);
}
}
export default App;
解决方法
在您的烧瓶代码中,如果您想连续流式传输,则需要在循环中调用 next(),现在可以通过放置一个带有睡眠时间的无限循环来完成,
@socket.on('event_stream')
def test_connect():
def generate():
fname = "./src/console.log"
with open(fname,"r+") as f:
yield f.read()
while True:
emit_data = next(generate())
socket.sleep(2)
emit('custom-server-msg',{'data':emit_data})
否则,如果日志文件过于连续更新,则可以使用 os.stat(FILE_NAME).st_mtime 来检查正在更新的文件的时间戳,如果日志文件中有任何更改, next() 将被调用以流式传输它:
@socket.on('event_stream')
def test_connect():
cached_stamp = 0
def generate():
fname = "./src/console.log"
with open(fname,"r+") as f:
yield f.read()
while True:
stamp = os.stat('./src/console.log').st_mtime
if stamp != cached_stamp:
cached_stamp = stamp
emit_data = next(generate())
emit('topo-server-msg',{'data':emit_data})