Python语音通话App加入语音频道后崩溃 附双端代码求排查方案
语音通话应用加入频道崩溃、无法连接服务端排查
已定位的直接导致故障的代码问题
客户端侧问题
- 音频发送逻辑错误:
sendData线程中直接将PyAudio的输入流对象当作音频数据通过socket发送,没有实际从流中读取采集到的音频帧,socket发送非字节类型数据会直接触发类型错误。 - 音频接收逻辑完全写反:
recive线程没有从socket读取服务端转发的远端音频,反而持续读取本地麦克风采集的数据直接写到本地扬声器,完全没有走网络传输链路。 - 全链路裸异常捕获静默吞错:两个工作线程的
except块没有任何日志打印逻辑,所有运行时错误都被直接跳过,这就是崩溃时看不到任何报错信息的核心原因。 - 资源回收逻辑缺失:异常触发后音频流、socket连接没有被统一回收,守护线程未配置,很容易触发资源泄漏导致进程无响应崩溃。
服务端侧问题
- 异常处理变量作用域错误:
handleVC函数异常块中调用的conn是主监听循环的全局变量,不是当前触发断连的客户端连接fromConnection,多用户接入时这里会直接抛出未定义变量错误,失效连接无法被正确清理,还可能误关正常用户的连接。 - Socket未配置基础参数:没有开启地址重用,服务端重启时容易出现端口占用导致绑定失败;没有配置超时机制,客户端异常断连后残留的无效连接会一直留在客户端列表,转发数据时持续触发断管错误。
- 无异常日志:所有运行时错误被裸
except吞掉,无法定位连接异常原因。
修复后可运行代码参考
服务端代码
import socket import threading import sys def on_server_stop(): log(consoleLog="Stopping Vc Server") sys.exit() host = '0.0.0.0' port = 5000 server = socket.socket() # 开启地址重用,避免重启端口占用 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((host, port)) server.listen() log(consoleLog='Voice call server started and online!') clientsInVC = [] # 加线程锁,避免多线程同时修改客户端列表出问题 list_lock = threading.Lock() def handleVC(fromConnection): log(consoleLog="User connected to VC server.") while True: try: data = fromConnection.recv(4096) if not data: # 收到空数据代表连接断开 raise ConnectionError("client disconnected") # 遍历转发时加锁,避免列表遍历过程中被其他线程修改 with list_lock: for client in clientsInVC.copy(): if client != fromConnection: try: client.send(data) except: client.close() clientsInVC.remove(client) except Exception as e: # 异常时清理当前连接 with list_lock: if fromConnection in clientsInVC: fromConnection.close() clientsInVC.remove(fromConnection) log(consoleLog=f"User left VC server, reason: {str(e)}") break while True: conn, addr = server.accept() with list_lock: clientsInVC.append(conn) thread = threading.Thread(target=handleVC, args=(conn,), daemon=True) thread.start()
客户端代码
import pyaudio import socket import threading def JOINVC(): print("started vc") vcclient = socket.socket() # 注意:如果服务端不在本机,这里要改成服务端实际IP,不要用127.0.0.1回环地址 host = "127.0.0.1" port = 5000 try: vcclient.connect((host, port)) except Exception as e: print(f"连接语音服务失败: {str(e)}") return p = pyaudio.PyAudio() Format = pyaudio.paInt16 Chunks = 4096 # 和服务端recv缓冲区大小对齐,减少音频卡顿 Channels = 1 Rate = 44100 inputStream = p.open(format=Format, channels=Channels, rate=Rate, input=True, frames_per_buffer=Chunks) outputStream = p.open(format=Format, channels=Channels, rate=Rate, output=True, frames_per_buffer=Chunks) def sendData(): while True: try: # 从麦克风读取音频帧再发送 data = inputStream.read(Chunks, exception_on_overflow=False) vcclient.send(data) except Exception as e: print(f"发送线程异常: {str(e)}") break inputStream.close() def recive(): while True: try: # 从socket读取远端音频再播放 data = vcclient.recv(Chunks) if not data: raise ConnectionError("server disconnected") outputStream.write(data, exception_on_underflow=False) except Exception as e: print(f"接收线程异常: {str(e)}") break outputStream.close() sendThread = threading.Thread(target=sendData, daemon=True) sendThread.start() reciveThread = threading.Thread(target=recive, daemon=True) reciveThread.start()
额外注意事项
- 跨设备测试时先确认服务端5000端口的防火墙已经放开,客户端填写的服务端IP是局域网/公网可访问的实际IP。
- 如果后续需要优化多人语音体验,可以给音频包增加序号、做抖动缓冲,避免音频卡顿、乱序。
内容的提问来源于stack exchange,提问作者No-Question123
相关产品推荐
相关产品推荐

