RPi3(CentOS7) SSH检测LED脚本作为systemd服务异常求助
我来帮你捋捋这个问题——咱们先从进程终止失败的核心原因说起,再一步步搞定systemd服务的异常。
1. 进程终止失败的核心原因
你提到手动发送-2(SIGINT)信号能关闭LED,但脚本里没法终止Python进程,大概率是信号没有精准发送到目标进程,或者你没正确记录Python脚本的PID。
常见错误点&修复方式:
错误1:未记录Python脚本的PID
启动Python脚本时必须把它的PID存下来,不然后续没法针对性发送信号。修改启动逻辑:# 启动LED脚本并将PID写入临时文件 python3 your_led_script.py & echo $! > /tmp/ssh_led_script.pid终止时读取PID并发送信号:
# 读取PID并发送SIGINT信号 PID=$(cat /tmp/ssh_led_script.pid) kill -2 $PID # 等待进程优雅退出,清理PID文件 wait $PID 2>/dev/null rm -f /tmp/ssh_led_script.pid错误2:进程匹配/信号选择错误
如果用pkill python3这种方式杀进程,很可能误杀其他Python程序,一定要精准定位你的LED脚本进程。另外,部分Python脚本会忽略SIGINT,可以先尝试SIGTERM(kill -15),如果还是不行再用SIGKILL(kill -9)——优先用优雅信号,避免强制终止带来的问题。错误3:权限不匹配
如果bash脚本通过systemd运行,可能和你手动运行的用户不一致,导致PID文件读写失败,或者没有权限给Python进程发信号。要确保systemd服务的运行用户和Python进程的用户一致,或者赋予足够的权限。
2. SSH连接检测的准确性优化
你当前的ssh_status=disconnected只是初始化值,得确保检测逻辑不会误判。推荐两种可靠的检测方式:
# 方式1:通过who命令检测SSH登录会话(排除自身进程) ssh_connections=$(who | grep -c "pts/" | grep -v $$) if [ $ssh_connections -gt 0 ]; then ssh_status=connected else ssh_status=disconnected fi
或者用ss命令检测22端口的活跃连接:
# 方式2:检测22端口的ESTABLISHED状态连接 ssh_connections=$(ss -t state established '( dport = :22 or sport = :22 )' | wc -l) # 减去ss命令自身的输出行 if [ $((ssh_connections - 1)) -gt 0 ]; then ssh_status=connected else ssh_status=disconnected fi
3. Systemd服务不符合预期的修复
脚本作为systemd服务运行时,常见问题是服务类型设置错误、缺少循环检测逻辑、日志无输出,或者权限配置不当。
正确的systemd服务文件示例(/etc/systemd/system/ssh-led-monitor.service):
[Unit] Description=SSH Connection LED Monitor After=network.target [Service] Type=simple User=pi # 替换成你运行脚本的用户 ExecStart=/path/to/your_monitor_script.sh Restart=always # 脚本意外退出时自动重启 RestartSec=5 StandardOutput=journal+console # 日志输出到journalctl,方便调试 [Install] WantedBy=multi-user.target
完善脚本的循环检测逻辑
脚本需要持续运行检测SSH状态,不能只执行一次。完整的循环示例:
#!/bin/bash # 初始化状态 ssh_status=disconnected led_status=off PID_FILE="/tmp/ssh_led_script.pid" while true; do # 检测SSH连接状态 ssh_connections=$(who | grep -c "pts/" | grep -v $$) # 有SSH连接且LED未启动时,启动脚本 if [ $ssh_connections -gt 0 ] && [ "$led_status" = "off" ]; then python3 /path/to/your_led_script.py & echo $! > $PID_FILE led_status=on echo "SSH connected: started LED script (PID: $(cat $PID_FILE))" # 无SSH连接且LED已启动时,终止脚本 elif [ $ssh_connections -eq 0 ] && [ "$led_status" = "on" ]; then if [ -f $PID_FILE ]; then PID=$(cat $PID_FILE) kill -2 $PID wait $PID 2>/dev/null rm -f $PID_FILE led_status=off echo "SSH disconnected: stopped LED script" fi fi # 每隔5秒检测一次,可根据需求调整间隔 sleep 5 done
Systemd服务调试技巧
- 查看服务状态:
systemctl status ssh-led-monitor.service - 实时查看日志:
journalctl -u ssh-led-monitor.service -f - 修改服务文件后重新加载:
systemctl daemon-reload - 启动/重启服务:
systemctl start ssh-led-monitor.service
额外注意事项
- 确保Python LED脚本正确处理
SIGINT信号,避免收到信号后LED残留亮灯:import signal import sys from blinkt import set_all, show, clear def handle_sigint(sig, frame): clear() show() sys.exit(0) signal.signal(signal.SIGINT, handle_sigint) - 先手动运行bash脚本验证逻辑没问题,再切换到systemd服务,降低调试难度。
- PID文件最好放在
/var/run目录(需要root权限),或者用唯一命名避免被其他进程覆盖,比如/tmp/ssh_led_monitor_$(id -u).pid。
内容的提问来源于stack exchange,提问作者Radim Lycka

