我想使用 Python 和 Flask Web 服务器,使用 WebSocket 将虚拟数据(随机的 4 个字符字符串)流式传输到 HTML 页面上的 div。 Python 和 HTML 的源代码如下。
main7.py
from flask import Flask, render_template
from flask_socketio import SocketIO
import random
import string
app = Flask(__name__)
socketio = SocketIO(app)
@app.route('/')
def index():
return render_template('index7.html')
def generate_random_chars():
while True:
random_chars = ''.join(random.choices(string.ascii_letters + string.digits, k=4))
socketio.emit('update', random_chars)
socketio.sleep(2)
if __name__ == '__main__':
socketio.start_background_task(target=generate_random_chars)
socketio.run(app, host='localhost', port=5000, debug=True)
index7.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flask WebSocket Test</title>
</head>
<body>
<div id="random-chars">Waiting for updates...</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script>
<script>
const socket = io();
socket.on('update', function(data) {
document.getElementById('random-chars').innerText = data;
});
</script>
</body>
</html>
页面的服务没有错误,并且似乎建立了 WebSocket 连接,但此后,网络流量中没有出现任何发出的消息。 Flask 调试输出或 DevTools 控制台也没有错误消息。
* Restarting with watchdog (inotify)
* Debugger is active!
* Debugger PIN: 136-937-281
(210008) wsgi starting up on http://127.0.0.1:5000
(210008) accepted ('127.0.0.1', 49994)
127.0.0.1 - - [29/Aug/2024 19:48:45] "GET / HTTP/1.1" 200 640 0.003211
(210008) accepted ('127.0.0.1', 49998)
127.0.0.1 - - [29/Aug/2024 19:48:45] "GET / HTTP/1.1" 400 293 0.001261
127.0.0.1 - - [29/Aug/2024 19:49:04] "GET / HTTP/1.1" 200 611 0.002471
127.0.0.1 - - [29/Aug/2024 19:49:04] "GET /socket.io/?EIO=4&transport=polling&t=P6V2cR7 HTTP/1.1" 200 278 0.000470
(210008) accepted ('127.0.0.1', 42628)
(210008) accepted ('127.0.0.1', 42634)
127.0.0.1 - - [29/Aug/2024 19:49:04] "POST /socket.io/?EIO=4&transport=polling&t=P6V2cRC&sid=WyHUScU-T8s22PT_AAAA HTTP/1.1" 200 219 0.001391
127.0.0.1 - - [29/Aug/2024 19:49:04] "GET /socket.io/?EIO=4&transport=polling&t=P6V2cRD&sid=WyHUScU-T8s22PT_AAAA HTTP/1.1" 200 213 0.000228
127.0.0.1 - - [29/Aug/2024 19:49:04] "GET /socket.io/?EIO=4&transport=polling&t=P6V2cRM&sid=WyHUScU-T8s22PT_AAAA HTTP/1.1" 200 181 0.000252
127.0.0.1 - - [29/Aug/2024 19:49:48] "GET /socket.io/?EIO=4&transport=websocket&sid=WyHUScU-T8s22PT_AAAA HTTP/1.1" 200 0 43.720072
127.0.0.1 - - [29/Aug/2024 19:49:48] "GET / HTTP/1.1" 200 611 0.001028
127.0.0.1 - - [29/Aug/2024 19:49:48] "GET /socket.io/?...
任何对问题的见解表示赞赏!
解决方案是避免用户 Woodford 指出的竞争条件,特别是仅在建立 WebSocket 连接后才启动发出任务。
下面是修改后的工作代码,在客户端提供额外的网络状态报告:
主.py
from datetime import datetime
import logging
from flask import Flask, render_template
from flask_socketio import SocketIO
app = Flask(__name__)
socketio = SocketIO(app)
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@app.route('/')
def index():
return render_template('index.html')
def generate_time_str():
while True:
time_str = str(datetime.now())
logger.info(f"Emitting: {time_str}")
socketio.emit('update', time_str)
socketio.sleep(1)
@socketio.on('connect')
def handle_connect():
logger.info("Client connected")
socketio.start_background_task(target=generate_time_str)
if __name__ == '__main__':
socketio.run(app, host='localhost', port=5000, debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flask WebSocket Test</title>
<style>
.error { color: red; }
.connected { color: green; }
.disconnected { color: orange; }
</style>
</head>
<body>
<div id="server-data"></div>
<div id="network-status">Connecting to server...</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const socket = io({
reconnection: true,
reconnectionAttempts: Infinity,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
timeout: 20000,
});
const randomCharsDiv = document.getElementById('server-data');
const networkStatusDiv = document.getElementById('network-status');
function updateNetworkStatus(message, className) {
networkStatusDiv.textContent = message;
networkStatusDiv.className = className;
}
socket.on('connect', function() {
console.log('Connected to server');
updateNetworkStatus('Connected to server', 'connected');
});
socket.on('update', function(data) {
console.log('Received update:', data);
randomCharsDiv.textContent = data;
});
socket.on('disconnect', function(reason) {
console.log('Disconnected from server:', reason);
updateNetworkStatus('Disconnected from server', 'disconnected');
});
socket.on('connect_error', function(error) {
console.error('Connection error:', error);
updateNetworkStatus('Error connecting to server', 'error');
});
socket.on('reconnect_attempt', function(attemptNumber) {
console.log('Attempting to reconnect:', attemptNumber);
updateNetworkStatus(`Attempting to reconnect (${attemptNumber})`, 'disconnected');
});
socket.on('reconnect', function(attemptNumber) {
console.log('Reconnected on attempt:', attemptNumber);
updateNetworkStatus('Reconnected to server', 'connected');
});
socket.on('reconnect_error', function(error) {
console.error('Reconnection error:', error);
updateNetworkStatus('Error reconnecting to server', 'error');
});
socket.on('reconnect_failed', function() {
console.error('Failed to reconnect');
updateNetworkStatus('Failed to reconnect to server', 'error');
});
});
</script>
</body>
</html>