You need to enable JavaScript to run this app. 使用flask_socketio与Socket.IO实现实时音频流的代码问题排查
优惠活动
大模型
产品
解决方案
定价
更多

使用flask_socketio与Socket.IO实现实时音频流的代码问题排查

现有代码核心问题梳理
  • 服务端音频读取逻辑完全失效
    代码在全局作用域打开音频文件时,逐次读8字节的循环在服务启动阶段就已经跑完,循环退出时data变量最终存储的是文件末尾读到的空值,全程没有把读到的音频块做持久化存储。等客户端真的连上来时,根本没有有效音频数据可以发。
  • 服务端通信逻辑存在阻塞死循环
    客户端连接触发的handleMessage里写了无退出条件的while True,一旦执行就会无限循环发残差的空数据,直接把SocketIO的事件循环堵死,后续所有连接、消息都没法正常处理。
  • 二进制传输通道用错了
    send方法默认走文本消息通道,直接把WAV的原始二进制字节塞进文本通道传输,会发生编码错乱,客户端拿到的根本不是能解析的有效二进制数据。
  • 前端音频处理逻辑完全不匹配
    代码里每收到零散的字节块就直接跑new Audio(msg),这个API要求传完整可解析的音频URL/Blob对象,零散的8字节碎片根本识别不了,直接触发播放报错。
    没有设计二进制块的拼接、缓冲逻辑,根本没法把零散接收到的字节重组为完整的可播放音频文件。
    SocketIO前后端版本如果不匹配,会直接协议握手失败,连稳定连接都建不起来。
修正后的可运行实现

服务端修正代码(server.py)

修正逻辑:提前把音频文件拆成固定大小的块存入内存、通过二进制通道逐块推送、加合理延时匹配实时流节奏、避免阻塞事件循环

from flask import Flask
from flask_socketio import SocketIO
import time

app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecret'
# 指定threading异步模式避免阻塞事件循环
socketio = SocketIO(app, cors_allowed_origins='*', async_mode='threading')

# 提前加载音频文件,拆分为固定大小的块存入内存列表
audio_chunks = []
CHUNK_SIZE = 4096  # 每块4KB,平衡网络开销和实时性
with open("bensound-spinningcollins.wav", "rb") as fwav:
    while True:
        chunk = fwav.read(CHUNK_SIZE)
        if not chunk:
            break
        audio_chunks.append(chunk)

# 监听客户端连接事件,连接建立后自动推送音频块
@socketio.on('connect')
def stream_audio_to_client():
    print('检测到客户端连接,开始推送音频流')
    # 逐块推送,加20ms延时模拟实时流式传输节奏
    for chunk in audio_chunks:
        # 以二进制类型发送自定义事件的消息,避免编码错乱
        socketio.emit('audio_chunk', chunk, binary=True)
        time.sleep(0.02)

if __name__ == '__main__':
    socketio.run(app, debug=False)

前端修正代码

修正逻辑:接收过程中缓存所有音频块、全部接收完成后拼接为完整WAV Blob、绑定到原生音频播放器实现播放

<html>
<head>
<title>实时音频流测试</title>
<script src="https://cdn.socket.io/3.1.1/socket.io.min.js"></script>
<style>
body {
    font-family: system-ui, sans-serif;
    max-width: 800px;
    margin: 2rem auto;
}
</style>
</head>
<body>
<h3>服务端音频流接收</h3>
<audio id="audioPlayer" controls style="width: 100%;"></audio>
<script type="text/javascript">
const socket = io.connect('http://127.0.0.1:5000');
// 缓存接收到的音频二进制块
let audioChunkBuffer = [];

socket.on('connect', function() {
    console.log('已成功连接到服务端');
});

// 监听服务端推送的音频块事件
socket.on('audio_chunk', function(chunk) {
    audioChunkBuffer.push(chunk);
});

// 连接断开时(所有音频块接收完成)自动生成可播放音频
socket.on('disconnect', function() {
    if (audioChunkBuffer.length === 0) return;
    // 将零散的二进制块拼接为完整的WAV格式Blob
    const audioBlob = new Blob(audioChunkBuffer, {type: 'audio/wav'});
    // 生成临时可访问的音频URL
    const audioPlayUrl = URL.createObjectURL(audioBlob);
    // 绑定到页面播放器
    document.getElementById('audioPlayer').src = audioPlayUrl;
});
</script>
</body>
</html>
落地注意事项
  • 音频块大小不要设置为原来的8字节,网络请求的开销会远大于音频数据本身,4KB~32KB的块大小是比较平衡的选择
  • 如果要实现真正的边接收边播放(不需要等全量音频下载完成),需要引入Web Audio API做实时解码,将接收到的字节流直接送入音频解码缓冲,避免全量缓存带来的等待延迟
  • 运行前确保bensound-spinningcollins.wav音频文件和server.py存放在同一目录,否则会触发文件找不到的报错
  • 安装依赖时要保证python-socketio和前端引入的socket.io版本匹配,推荐前端用3.x版本时,服务端安装python-socketio==4.6.1、flask-socketio==4.3.1,避免协议不兼容的连接问题

内容的提问来源于stack exchange,提问作者Mike_Vahe Moubayed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.04 10:36:04