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

Python中socket recvfrom()捕获UDP/组播数据时阻塞挂起求助

UDP广播与组播接收挂起问题排查

环境与前提

  • 网卡静态IP:10.10.10.88
  • Wireshark已捕获到目标数据包(广播包源IP10.10.10.120、目标255.255.255.255、端口2222;组播包源IP10.10.10.101、目标238.1.0.101、端口50101),排除防火墙拦截问题
  • 运行代码时未开启Wireshark

问题现象

两段Python代码调用recvfrom()时均出现永久挂起,且无法通过Ctrl+C终止进程,只能强制杀死。

1. UDP广播接收代码及问题

代码:

import socket

# IP address associated with the network interface
ip_address = '10.10.10.88'  
port = 2222  # port I'm listening on

# Create a UDP socket and bind it to the IP address
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind((ip_address, port))

print(f"Listening for UDP packets on {ip_address}:{port}")

try:
    while True:
        print('test1')
        data, addr = udp_socket.recvfrom(1024)  
        print('test2')
        
        # Print the received packet data as hexadecimal
        print(f"Received packet from {addr}: {data.hex()}")
except KeyboardInterrupt:
    print("Capture stopped by user (Ctrl+C).")

udp_socket.close()

程序输出:

Listening for UDP packets on 10.10.10.88:2222
test1

程序卡在recvfrom()调用处,无后续输出,Ctrl+C无法终止。

2. 组播接收代码及问题

代码:

import socket
import struct

# Specify the multicast group address and port
multicast_group = '238.1.0.101'
multicast_port = 50101

# Create a UDP socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# Set the socket to allow reuse of the address (in case it's used by other processes)
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# Bind the socket to the specified multicast address and port
udp_socket.bind(('', multicast_port))

# Set the IP_ADD_MEMBERSHIP option to join the multicast group
mreq = struct.pack('4sl', socket.inet_aton(multicast_group), socket.INADDR_ANY)
udp_socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

print(f"Listening for multicast packets on {multicast_group}:{multicast_port}")

try:
    while True:
        print('test1')
        data, addr = udp_socket.recvfrom(1024)  
        print('test2')
        # Print the received packet data as hexadecimal
        print(f"Received packet from {addr}: {data.hex()}")
except KeyboardInterrupt:
    print("Capture stopped by the user (Ctrl+C).")

udp_socket.close()

程序输出:

Listening for multicast packets on 238.1.0.101:50101
test1

同样卡在recvfrom()调用处,Ctrl+C无法终止进程。

排查建议

  1. 调整socket绑定逻辑

    • 广播接收代码尝试将绑定IP改为''或'0.0.0.0',确保接收所有接口的广播包:
      udp_socket.bind(('', port))
      
    • 组播代码可尝试绑定到网卡特定IP10.10.10.88,而非空字符串,确认组播包是否被正确转发到目标接口。
  2. 添加socket超时配置
    给socket设置超时时间,避免永久挂起,同时让Ctrl+C能正常触发信号处理:

    udp_socket.settimeout(5)  # 设置5秒超时
    

    同时在循环中捕获socket.timeout异常,维持循环运行,这样既可以验证是否真的收不到包,也能让进程正常响应中断信号。

  3. 验证组播配置有效性

    • 用系统命令检查组播组加入状态:Linux用ip maddr show,Windows用netsh interface ip show joins
    • 修改组播成员资格绑定逻辑,指定到当前网卡IP:
      mreq = struct.pack('4sl', socket.inet_aton(multicast_group), socket.inet_aton('10.10.10.88'))
      
  4. 检查端口占用情况
    用系统命令确认端口是否被其他进程占用:Linux用netstat -anp | grep 端口号,Windows用netstat -ano | findstr 端口号,确保当前程序的socket正确绑定目标端口。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 14:33:15