You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python UDP套接字recvfrom阻塞无数据问题(终端/C#可正常运行)

UDP音频流接收问题:Python sock.recvfrom() 阻塞但Wireshark显示有数据包

问题背景

我有一台模拟转数字音频的设备,通过UDP协议推送音频流到本地服务器。使用终端命令echo 'subscribe' | nc -u 192.168.0.194 9444或C#代码都能正常接收约15秒的响应数据,但Python脚本调用sock.recvfrom()时始终阻塞超时,尽管Wireshark明确显示设备已向我的笔记本发送UDP数据包。需要找出问题原因并解决,最终实现音频播放。

可能的原因

  • 套接字绑定地址错误:如果Python脚本绑定了127.0.0.1,只能接收本地回环数据包,无法获取设备从局域网发来的流量
  • 端口不匹配:Wireshark中显示的数据包目标端口,和Python脚本监听的端口不一致
  • 套接字配置问题:未设置SO_REUSEADDR/SO_REUSEPORT导致端口占用,或超时时间设置过短
  • 网络权限限制:Python进程被防火墙拦截(即使nc和C#能正常接收,Python可能未被添加到防火墙允许列表)
  • UDP连接特性忽略:UDP是无连接协议,设备可能将音频流发回订阅命令的源端口,如果Python用不同套接字发送订阅和接收数据,会导致接收不到

解决办法

  1. 绑定到全局地址:将套接字绑定到0.0.0.0,确保能接收所有网卡的 incoming 流量
  2. 核对端口一致性:用Wireshark确认设备发送数据包的目标端口,确保Python监听的端口完全匹配
  3. 调整套接字配置:添加端口复用选项,先关闭超时设置测试接收
  4. 检查防火墙权限:临时关闭防火墙测试,或手动将Python.exe添加到防火墙允许列表
  5. 复用同一套接字:用同一个套接字发送订阅命令和接收音频流,确保设备能将数据发回正确的源端口

修正后的Python接收代码示例

import socket

DEVICE_IP = "192.168.0.194"
DEVICE_PORT = 9444
LOCAL_LISTEN_PORT = 9444  # 与Wireshark显示的目标端口一致

# 创建UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 允许端口复用,避免端口占用问题
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定到所有网卡的指定端口
sock.bind(("0.0.0.0", LOCAL_LISTEN_PORT))
# 先注释超时设置,确认能接收数据后再调整
# sock.settimeout(15)

# 发送订阅命令
sock.sendto(b"subscribe", (DEVICE_IP, DEVICE_PORT))

print("等待接收音频数据...")
try:
    while True:
        data, addr = sock.recvfrom(4096)  # 缓冲区大小根据音频包调整
        print(f"来自{addr}的数据包,长度:{len(data)}")
        # 后续处理音频数据
except KeyboardInterrupt:
    print("手动终止接收")
finally:
    sock.close()

音频播放实现(基于PyAudio)

假设设备输出的是16位单声道PCM音频,可通过pyaudio直接播放:

  1. 安装依赖:pip install pyaudio
  2. 整合播放逻辑的代码:
import socket
import pyaudio

# 设备配置
DEVICE_IP = "192.168.0.194"
DEVICE_PORT = 9444
LOCAL_LISTEN_PORT = 9444

# 音频参数(需匹配设备输出格式,参考设备说明书)
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100

# 初始化UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(("0.0.0.0", LOCAL_LISTEN_PORT))
sock.sendto(b"subscribe", (DEVICE_IP, DEVICE_PORT))

# 初始化音频播放流
p = pyaudio.PyAudio()
stream = p.open(
    format=FORMAT,
    channels=CHANNELS,
    rate=RATE,
    output=True,
    frames_per_buffer=CHUNK
)

print("开始播放音频...")
try:
    while True:
        data, _ = sock.recvfrom(CHUNK * 2)  # 16位PCM每个样本占2字节
        stream.write(data)
except KeyboardInterrupt:
    print("停止播放")
finally:
    stream.stop_stream()
    stream.close()
    p.terminate()
    sock.close()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 12:45:00