Flask屏幕共享应用白屏加载异常,请求代码排查
Flask屏幕共享应用白屏问题排查与修复
代码中的核心问题
- 错误启动线程调用路由函数:主函数里的线程启动代码完全多余,
screen_sharing是Flask路由函数,只有客户端请求/screen_sharing时才会触发,直接通过线程调用会在无请求上下文的情况下执行,还会提前阻塞Socket连接,毫无实际作用。 - Socket接收逻辑阻塞请求:
generate_frames里的内层循环会一直调用recv直到返回空包,这意味着只有当Socket连接断开时才会进入帧处理步骤。如果服务端持续发送数据,这个循环会无限等待,永远不会解码帧,导致网页请求一直挂起,出现白屏。 - 缺少对应服务端发送数据:你的代码只有Flask客户端部分,没有实现屏幕捕获并发送帧数据的服务端程序。没有服务端的情况下,
client_socket.recv会一直阻塞,请求永远得不到响应。 - Socket连接无异常处理:连接服务端时没有设置超时或错误处理,一旦服务端未启动,请求会一直挂起,没有任何报错提示。
修复步骤
- 删除无用线程代码:把主函数里的线程启动相关代码全部删掉,Flask会自动处理路由请求。
- 修改Socket帧接收逻辑:和服务端约定帧传输格式,先发送帧的长度,再发送帧数据,避免无限等待:
import struct # 需要导入struct模块 @app.route('/screen_sharing') def screen_sharing(): client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.settimeout(5) try: client_socket.connect(('192.168.1.112', 5000)) except Exception as e: print(f"连接失败: {str(e)}") return Response("无法连接到屏幕共享服务", status=500) client_socket.settimeout(None) def generate_frames(): while True: try: # 接收帧长度(4字节大端格式) len_bytes = client_socket.recv(4) if not len_bytes: break frame_len = struct.unpack('!I', len_bytes)[0] # 接收完整帧数据 data = b'' while len(data) < frame_len: chunk = client_socket.recv(min(4096, frame_len - len(data))) if not chunk: break data += chunk if len(data) != frame_len: continue frame = np.frombuffer(zlib.decompress(data), dtype=np.uint8) frame = cv2.imdecode(frame, 1) if frame is not None: _, buffer = cv2.imencode('.jpg', frame) yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + buffer.tobytes() + b'\r\n') except Exception as e: print(f"帧处理错误: {str(e)}") client_socket.close() break return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
- 编写对应服务端代码:使用
mss捕获屏幕,压缩后按约定格式发送数据:
import socket import zlib import struct from mss import mss import cv2 import numpy as np SERVER_IP = '0.0.0.0' SERVER_PORT = 5000 def send_screen_frames(conn): with mss() as sct: monitor = sct.monitors[1] # 捕获主屏幕 while True: try: img = sct.grab(monitor) frame = np.array(img) frame = cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR) _, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 80]) compressed_data = zlib.compress(buffer.tobytes()) # 发送帧长度和数据 conn.sendall(struct.pack('!I', len(compressed_data))) conn.sendall(compressed_data) except Exception as e: print(f"服务端错误: {str(e)}") break with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((SERVER_IP, SERVER_PORT)) s.listen() print(f"服务端监听 {SERVER_IP}:{SERVER_PORT}") conn, addr = s.accept() with conn: print(f"客户端连接: {addr}") send_screen_frames(conn)
- 开启Flask多线程模式:修改
app.run为app.run(host='0.0.0.0', port=5000, threaded=True),支持同时处理页面请求和帧流传输。
内容的提问来源于stack exchange,提问作者Hassan Shehzad
相关产品推荐
相关产品推荐

