Ubuntu 收不到消息的定位与修复指南
一、先快速定位问题归属
- 明确消息类型:是系统桌面通知(如右上角气泡)、本地进程间通信(如 D-Bus)、还是网络消息(UDP/TCP/组播/广播)。
- 网络类先用抓包确认链路:在终端执行 sudo tcpdump -i <网卡名> port <端口> or multicast or broadcast,观察是否有报文到达本机。能抓到但应用收不到,多为应用/路由/内核参数问题;抓不到,多为网络路径或发送端问题。
- 桌面通知类:检查系统设置→通知,确认应用被允许发送通知,且未静音/勿扰;必要时重启通知服务(见下文命令)。
二、如果是系统桌面通知收不到
- 检查并重启通知服务(不同桌面环境服务名不同):
- GNOME:检查“设置→通知”,确认目标应用启用;必要时执行:systemctl --user restart gnome-shell 或 killall -HUP gnome-shell(会话级,谨慎)。
- KDE:检查“系统设置→通知”,重启 plasmashell:kquitapp5 plasmashell && kstart5 plasmashell。
- Xfce:检查“设置→通知”,可用 xfce4-notifyd-config 验证守护进程运行。
- 若安装了第三方通知守护进程(如 dunst),确保其已启动:systemctl --user status dunst;必要时 systemctl --user restart dunst。
- 注意:某些应用需“前台运行”或“在通知白名单”中才会显示。
三、如果是网络 UDP 组播收不到
- 抓包确认链路:sudo tcpdump -i -nn host <组播IP> and port <端口>。若抓不到,排查交换机 IGMP Snooping、发送端是否正确 join/send、VLAN/ACL 等网络侧配置。
- 正确加入组播组(示例代码要点):
- 创建 socket 后设置 TTL(建议 32):setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))
- 指定收流网卡:struct ip_mreqn mreq = { .imr_ifindex = if_nametoindex(“eth0”) }; setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
- 绑定地址用 INADDR_ANY:bind(s, (struct sockaddr*)&addr, sizeof(addr)); 端口与发送端一致。
- 路由与 IGMP 保活(常见根因):
- 多网卡/复杂路由时,确保组播/默认路由从收流网卡发出,否则 IGMP 查询/应答可能走错接口,交换机停止转发组播流。可临时添加:sudo ip route add default dev <收流网卡>;或添加 224.0.0.0/4 的直连路由:sudo ip route add 224.0.0.0/4 dev <收流网卡>。注意这会影响该接口的其他流量,生产环境请结合策略路由精细配置。
- 某些环境下,仅添加 224.0.0.0/4 可能在一段时间后停止收流,改为默认路由可稳定保活(与 IGMPv2 查询机制相关)。
- 防火墙放行(UFW/iptables):
- UFW:sudo ufw allow <端口>/udp
- nftables/iptables:sudo nft add rule inet filter input udp dport <端口> accept 或 sudo iptables -I INPUT -p udp -d 224.0.0.0/4 --dport <端口> -j ACCEPT
- 程序绑定与地址选择:接收端 bind 用 INADDR_ANY,发送端 join 到正确的 接口索引;必要时在发送端也显式设置出站接口(IP_MULTICAST_IF)。
四、如果是网络 UDP 广播收不到
- 抓包验证:sudo tcpdump -i -nn udp port <端口> or broadcast。能抓到但应用收不到,常见于内核反向路径过滤(rp_filter)丢弃“源地址不可达”的报文。
- 临时放宽 rp_filter(测试用):
- sudo sysctl -w net.ipv4.conf.all.rp_filter=0
- sudo sysctl -w net.ipv4.conf.default.rp_filter=0
- 永久生效:编辑 /etc/sysctl.conf,设置 net.ipv4.conf.all.rp_filter=0 与 net.ipv4.conf.default.rp_filter=0,然后 sysctl -p。
- 应用层建议:bind 用 INADDR_ANY,并开启 SO_REUSEADDR,确保网卡能收到广播并能正确入站。
五、如果是本地进程间通信消息收不到(D-Bus/ZeroMQ/自定义 socket)
- 确认进程在同一会话/用户/权限下;检查应用是否在前台、是否崩溃或无日志输出。
- D-Bus:用 dbus-monitor --session 或 dbus-monitor --system 观察是否有对应消息;必要时重启会话总线或目标服务(systemctl --user restart <服务名> 或 systemctl restart <服务名>)。
- 重启相关服务(通用):systemd 用 systemctl restart <服务名>;SysV/旧版可用 service <服务名> restart。修改配置后记得重启对应服务以生效。