ssdp发现失败主因是端口占用、多播配置错误及防火墙拦截;需检查1900端口占用、绑定具体ip而非""、设置so_reuseaddr/so_reuseport、加入239.255.255.250多播组、放行udp 1900入向流量、设recv超时、正确解析httpu响应并校验url。

SSDP 发现请求发不出去,socket 绑定失败怎么办
常见现象是调用 socket.bind(("", 1900)) 报 OSError: [Errno 98] Address already in use,或压根没收到任何响应。SSDP 依赖 UDP 多播,端口 1900 是保留端口,系统可能被其他 UPnP 服务(比如 Windows 的 SSDP Discovery Service、macOS 的 mDNSResponder)占着。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 先确认端口占用:
lsof -i :1900(macOS/Linux)或netstat -ano | findstr :1900(Windows),杀掉无关进程 - 绑定时别用
""(即 INADDR_ANY),改用具体本地多播接口 IP,比如"192.168.1.100";否则在多网卡机器上容易选错接口 - 必须设置
socket.SO_REUSEADDR,部分系统还要求SO_REUSEPORT(Linux/macOS),否则 bind 失败概率极高 - 发送目标地址必须是 SSDP 多播地址
"239.255.255.250",端口固定为1900,不能写错
发出了 M-SEARCH 却收不到响应,recvfrom 一直阻塞
不是服务没响应,大概率是 socket 没正确加入多播组,或者防火墙拦截了入向 UDP 包。SSDP 响应是从设备的随机端口发回的单播包,但很多实现(尤其 Python 示例)误以为响应也在多播地址上,结果监听错了地方。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 接收 socket 必须调用
setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, ...)加入239.255.255.250组,否则收不到 M-SEARCH 请求(虽然你发的是请求,但有些设备会把响应也发到多播组) - 更关键的是:响应是单播的,所以你得确保本机 UDP 端口
1900对外开放——检查防火墙是否放行入向 UDP 1900,特别是 Windows Defender 防火墙默认会拦 -
recvfrom超时一定要设,比如sock.settimeout(3),不然卡死在无响应场景下 - 不要只监听一个接口;如果机器有多个网卡(比如 WiFi + 以太网),需为每个活跃接口分别 bind + join group
收到响应但解析失败,Location 字段为空或格式异常
SSDP 响应是 HTTPU(HTTP over UDP)格式,但不是完整 HTTP 报文:没有状态行、头字段大小写不敏感、换行可能是 \r\n 或 \n,且某些设备(如老款路由器)会漏掉 LOCATION: 或写成 location:,甚至夹带不可见字符。
本文档主要讲述的是android rtsp流媒体播放介绍;实时流协议(RTSP)是应用级协议,控制实时数据的发送。RTSP提供了一个可扩展框架,使实时数据,如音频与视频,的受控、点播成为可能。数据源包括现场数据与存储在剪辑中数据。该协议目的在于控制多个数据发送连接,为选择发送通道,如UDP、组播UDP与TCP,提供途径,并为选择基于RTP上发送机制提供方法。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 别用标准
http.client解析响应;直接按行 split,对每行做strip().lower().startswith("location:")判断 - 提取 URL 后,务必用
urllib.parse.urlparse()校验 scheme 和 netloc,有些设备返回LOCATION: http://后面直接断了 - 注意 CRLF 和 LF 混用:用
response_bytes.replace(b"\r\n", b"\n").split(b"\n")统一换行再处理 - 部分设备(如某些 IoT 插座)会在响应里塞多个
LOCATION,取第一个非空、能 parse 成合法 URL 的即可
为什么用 asyncio 写 SSDP 发现反而更难稳定
异步本身不解决 SSDP 的本质问题,反而容易掩盖 socket 配置错误。比如 asyncio.DatagramProtocol 默认不帮你 setsockopt,也不自动 join 多播组,一旦忘了手动配,就彻底收不到包;而且 asyncio 的 UDP transport 在不同 Python 版本里对多播支持不一致(3.8+ 更稳,3.7 及以前有已知 bug)。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 除非整个项目已是 asyncio 架构,否则优先用同步 socket——简单、可控、调试直观
- 如果坚持用 asyncio,务必在
connection_made里手动调用transport.get_extra_info("socket").setsockopt(...)设置多播选项 - 避免在协程里反复创建/关闭 socket;SSDP 探测是短时密集操作,复用 socket 比每次新建更可靠
- 别信“async 自动处理超时”——UDP 丢包率高,仍要自己控制重试次数和间隔(比如最多发 3 次,间隔 0.5s)
多播地址、端口、TTL、套接字选项这四样,只要有一样配错,SSDP 就静默失效。最容易被忽略的是 TTL —— 默认是 1,跨子网发现必须显式设为 2 或更高,但多数示例根本不提这一句。









