背景介绍
我用Ubuntu 20.04搭建了一个小型的Linux服务器,并在局域网内用Windows电脑通过SSH连接这台服务器进行代码开发、编译等工作。服务器是通过一个USB无线网卡连接到路由器的WiFi。使用过程中经常遇到SSH连不上的情况,经过检查发现要么是服务器的WiFi断了,要么是服务器的某些核心进程卡死(怀疑也是断网导致的),且我设置了WiFi重连服务也不起作用。于是决定写一个状态监控服务,时刻盯着这台服务器的状态,一旦发现异常就尝试恢复。经过一番摸索,总结了下面这套十分奏效的方案。
实现步骤
1、创建一体化监控脚本
bash
sudo touch /usr/local/bin/unified-watchdog.sh
粘贴以下核心脚本(请仔细阅读注释,特别是需要你确认的配置项):
bash
#!/bin/bash
# 一体化监控服务 v3.0
# 设计原则:网络监控与系统心跳在独立子进程中运行,完全隔离
LOG_DIR="/var/log/unified-watchdog"
mkdir -p "$LOG_DIR"
NET_LOG="$LOG_DIR/network.log"
SYS_LOG="$LOG_DIR/system.log"
MAIN_LOG="$LOG_DIR/main.log"
# ========== 【请确认】你的网络配置 ==========
WIFI_INTERFACE="xxxxxxxxxxxxxxx" # 你的WiFi网卡接口名
CONNECTION_NAME="xxxxxxxx" # 你的WiFi名称
TEST_HOST="192.168.10.58" # 你的Windows电脑IP(用于测试)
GATEWAY="192.168.10.1" # 你的路由器网关IP(用`ip route show default`查看)
# ==========================================
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$MAIN_LOG"
}
# 函数:网络监控进程(专注于WiFi恢复)
network_monitor() {
log "网络监控子进程启动"
echo "$(date) 网络监控启动" >> "$NET_LOG"
local last_problem=""
local healthy_count=0
while true; do
# 诊断当前网络状态(分层诊断)
local problem=""
# 1. 物理层检查
if ! ip link show "$WIFI_INTERFACE" 2>/dev/null | grep -q "state UP"; then
problem="PHY_DOWN"
# 2. 网络层检查
elif ! ping -c 2 -W 1 -I "$WIFI_INTERFACE" "$GATEWAY" >/dev/null 2>&1; then
problem="GATEWAY_UNREACHABLE"
# 3. 传输层检查(TCP连通性)
elif ! timeout 3 curl -s --interface "$WIFI_INTERFACE" http://connect.rom.miui.com/generate_204 >/dev/null 2>&1; then
problem="INTERNET_BLOCKED"
fi
# 根据问题类型执行恢复
if [ -n "$problem" ]; then
echo "$(date) 检测到问题: $problem" >> "$NET_LOG"
# 避免对同一问题重复恢复
if [ "$problem" != "$last_problem" ] || [ $healthy_count -gt 3 ]; then
case $problem in
PHY_DOWN)
echo "$(date) 执行: 重启接口" >> "$NET_LOG"
ip link set "$WIFI_INTERFACE" down
sleep 2
ip link set "$WIFI_INTERFACE" up
;;
GATEWAY_UNREACHABLE)
echo "$(date) 执行: 刷新DHCP" >> "$NET_LOG"
nmcli connection down "$CONNECTION_NAME"
sleep 3
nmcli connection up "$CONNECTION_NAME"
;;
INTERNET_BLOCKED)
echo "$(date) 执行: 刷新DNS和路由" >> "$NET_LOG"
systemctl restart systemd-resolved
sleep 2
;;
esac
last_problem="$problem"
healthy_count=0
fi
else
# 网络健康
if [ -n "$last_problem" ]; then
echo "$(date) 网络恢复健康" >> "$NET_LOG"
last_problem=""
fi
((healthy_count++))
fi
# 动态检查间隔:有问题时检查密,健康时检查疏
if [ -n "$problem" ]; then
sleep 15
elif [ $healthy_count -lt 5 ]; then
sleep 20
else
sleep 45 # 长期健康后降低检查频率
fi
done
}
# 函数:系统心跳监控进程(绝不操作网络)
system_heartbeat() {
log "系统心跳子进程启动"
echo "$(date) 系统心跳启动" >> "$SYS_LOG"
local stall_count=0
local max_stalls=180 # 3分钟无响应才触发恢复
while true; do
# 仅测试最基本系统功能(不涉及网络)
# 1. 测试文件系统响应
if ! touch /tmp/.heartbeat_test 2>/dev/null; then
echo "$(date) 警告: 文件系统响应慢" >> "$SYS_LOG"
((stall_count++))
# 2. 测试内核proc接口响应
elif ! timeout 1 cat /proc/uptime >/dev/null 2>&1; then
echo "$(date) 警告: 内核接口响应慢" >> "$SYS_LOG"
((stall_count++))
# 3. 测试进程调度(简单计算)
elif ! expr 1 + 1 >/dev/null 2>&1; then
echo "$(date) 警告: 进程调度异常" >> "$SYS_LOG"
((stall_count++))
else
# 系统正常
if [ $stall_count -gt 0 ]; then
echo "$(date) 系统恢复响应" >> "$SYS_LOG"
stall_count=0
fi
fi
# 仅在持续卡死时才采取行动
if [ $stall_count -ge $max_stalls ]; then
echo "$(date) 警报: 系统持续无响应,执行安全重启" >> "$SYS_LOG"
# 只重启非关键服务,避免影响网络
systemctl --no-block restart systemd-journald
sleep 10
# 如果仍无响应,计划延迟重启(给手动干预机会)
if ! timeout 2 cat /proc/uptime >/dev/null 2>&1; then
echo "$(date) 计划5分钟后重启系统" >> "$SYS_LOG"
shutdown -r +5 "系统看门狗触发安全重启"
fi
stall_count=0
fi
sleep 5 # 系统检查间隔较短,但恢复阈值很高
done
}
# 主进程:启动并监控两个子进程
log "一体化监控服务启动"
echo "==========================================" >> "$MAIN_LOG"
echo "服务启动时间: $(date)" >> "$MAIN_LOG"
echo "网络接口: $WIFI_INTERFACE" >> "$MAIN_LOG"
echo "连接名称: $CONNECTION_NAME" >> "$MAIN_LOG"
echo "==========================================" >> "$MAIN_LOG"
# 启动网络监控子进程(后台运行)
network_monitor &
NET_PID=$!
log "网络监控PID: $NET_PID"
# 启动系统心跳子进程(后台运行)
system_heartbeat &
SYS_PID=$!
log "系统心跳PID: $SYS_PID"
# 主进程监控子进程状态
while true; do
if ! kill -0 $NET_PID 2>/dev/null; then
log "网络监控进程异常退出,重启中..."
network_monitor &
NET_PID=$!
fi
if ! kill -0 $SYS_PID 2>/dev/null; then
log "系统心跳进程异常退出,重启中..."
system_heartbeat &
SYS_PID=$!
fi
# 主进程每30秒记录一次状态
sleep 30
if [ $(( $(date +%s) % 300 )) -lt 30 ]; then
log "运行中: 网络PID=$NET_PID, 系统PID=$SYS_PID"
fi
done
2、设置权限和Systemd服务
bash
# 设置脚本权限
sudo chmod +x /usr/local/bin/unified-watchdog.sh
# 创建服务文件
sudo touch /etc/systemd/system/unified-watchdog.service
粘贴以下服务配置:
bash
[Unit]
Description=Unified WiFi and System Watchdog Service
After=network.target NetworkManager.service
Wants=NetworkManager.service
[Service]
Type=simple
ExecStart=/usr/local/bin/unified-watchdog.sh
Restart=always
RestartSec=10
User=root
# 资源限制,确保服务不会占用过多系统资源
CPUQuota=10%
MemoryLimit=50M
IOWeight=10
# 日志配置
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=unified-watchdog
[Install]
WantedBy=multi-user.target
3、启用并测试新服务
bash
# 1. 查看服务状态
sudo systemctl status unified-watchdog.service
# 2. 查看各模块日志
sudo tail -20 /var/log/unified-watchdog/main.log # 主进程日志
sudo tail -20 /var/log/unified-watchdog/network.log # 网络监控日志
sudo tail -20 /var/log/unified-watchdog/system.log # 系统心跳日志
# 3. 停止服务(如需调整配置)
sudo systemctl stop unified-watchdog.service
4、结束