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

如何在Windows系统下用Python接收UDP组播数据?排查接收失败问题

问题描述

我有一台设备通过USB连接到Windows 10机器,该设备会发送各类UDP组播包,Wireshark能在Windows机器上捕获到这些数据包。

我用Python 3.10.10写了如下脚本尝试接收数据:

import struct
import socket
import select

HOST = "192.168.200.5"
MCAST_GRP = "239.0.0.12"
PORT = 45013

def initSocket(group, port, host):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
    sock.bind(("0.0.0.0", port))
    # struct.pack converts non-bytes values to bytes. To be used as the last parameter of 
    # setsockopt which needs to be a bytes-like object representing a buffer.
    # "4sl" is a format specifier for a 4-bytes string and a long int.
    mreq = struct.pack("4sl", socket.inet_aton(group), socket.INADDR_ANY)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
    return sock

sock = initSocket(MCAST_GRP, PORT, HOST)
while True:
    ready = select.select([sock], [], [], 1)
    if ready[0]:
        data = sock.recv(4096)
        print(f"received message:  {data}")   
    else:
        print("No data received")

但脚本始终无法接收数据,仅输出No data received。已做的排查:

  • 以管理员身份运行脚本
  • 通过netstat -ano -p udp确认端口45013未被其他进程占用
  • 防火墙已允许Python应用通过

设备连接的以太网适配器IP为192.168.200.5,Wireshark验证电脑确实能接收UDP包。执行netsh int ip show join的结果:

Interface 25: Ethernet

Scope       References  Last  Address
----------  ----------  ----  ---------------------------------
0                    0  Yes   224.0.0.1
0                    4  Yes   224.0.0.251
0                    1  Yes   224.0.0.252
0                    3  Yes   239.255.255.250

另外,在Windows上的Linux虚拟机中,用C代码可以接收数据,但Python脚本报错:

Traceback (most recent call last):
  File "udp_receiver.py", line 54, in <module>
    sock = initSocket(MCAST_GRP, PORT, HOST)
  File "udp_receiver.py", line 32, in initSocket
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
OSError: [Errno 19] No such device
排查与解决方法

Windows上Python脚本收不到数据的修复

1. 绑定组播到指定网卡

当前脚本用socket.INADDR_ANY加入组播,Windows可能会把组播成员关系绑定到默认网卡,而非设备连接的192.168.200.5网卡。从netsh的输出看,目标组播239.0.0.12并未被加入到网卡25中,说明组播成员关系未生效到正确网卡。

修改mreq的构造,将socket.INADDR_ANY替换为设备网卡的IP,强制组播绑定到指定网卡:

mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.inet_aton(HOST))

2. 绑定socket到指定网卡IP

把bind的地址从"0.0.0.0"改成设备网卡的IP"192.168.200.5",限制socket只监听该网卡的流量:

sock.bind((HOST, port))

3. 启用组播环回(按需)

如果设备和Windows机器在同一虚拟网络栈下(比如USB虚拟网卡),开启组播环回确保本地能收到组播包:

sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)

修改后的完整initSocket函数:

def initSocket(group, port, host):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # 绑定到指定网卡IP
    sock.bind((host, port))
    # 绑定组播到指定网卡
    mreq = struct.pack("4sl", socket.inet_aton(group), socket.inet_aton(host))
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
    # 启用组播环回(按需开启)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
    return sock

Linux虚拟机中Python脚本报错的解决

报错OSError: [Errno 19] No such device是因为虚拟机网络模式问题,比如NAT模式下虚拟网卡无法直接访问Windows主机的USB网卡设备。

解决方法:

  • 将虚拟机网络模式改为桥接模式,让虚拟网卡和Windows主机的USB网卡处于同一网段,直接接收组播包
  • 或者修改脚本,将HOST替换为虚拟机自身的网卡IP(而非Windows主机的192.168.200.5),确保组播成员关系绑定到虚拟机存在的网卡上

替代方案:用Python直接抓包(类似Wireshark)

可以用scapy库(和Wireshark底层依赖一致)直接从网卡层面捕获UDP组播包,绕过系统socket的组播配置限制:

  1. 安装scapy:
pip install scapy
  1. 捕获指定组播和端口的脚本示例:
from scapy.all import sniff, UDP, IP

MCAST_GRP = "239.0.0.12"
PORT = 45013

def packet_handler(packet):
    if IP in packet and UDP in packet:
        if packet[IP].dst == MCAST_GRP and packet[UDP].dport == PORT:
            print(f"received message: {bytes(packet[UDP].payload)}")

# 指定监听的网卡名称(可从Wireshark中查看,比如"Ethernet")
sniff(iface="Ethernet", prn=packet_handler, store=0)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 12:30:04