背景
内网有好几台计算机和 NAS,但是家里的 UPS 只能向一台设备发送关机信号,不能向内网所有设备发送(没钱买智能 UPS)。但是确实有这个需求,忽然想到既然不能在发送端解决,但是可以在接收端解决啊,毕竟接收端都是智能设备,不是 Windows 就是 Linux,完全可以通过小脚本实现这个功能。
原理
首先将 UPS 连接到监控机(建议 NAS 或者是相对重要的机器),然后在内网其余设备各挂一个小脚本,小脚本的作用是监测监控机状态,如果监控机离线,则自动关机。
实现
这里我们通过 ping 来实现监控机状态的监测,以下提供 GO 和 Java 的实例,基本能覆盖 90% 的智能设备。
GO(Windows)
package main
import (
"fmt"
"os/exec"
"time"
)
func ping(ip string) bool {
cmd := exec.Command("ping", "-n", "1", ip)
err := cmd.Run()
return err == nil
}
func shutdown() {
cmd := exec.Command("shutdown", "/s", "/t", "0")
err := cmd.Run()
if err != nil {
fmt.Println("Failed to shutdown the system:", err)
} else {
fmt.Println("System is shutting down...")
}
}
func main() {
ip := "192.168.1.1" // 192.168.1.1 修改为监控机的实际 IP
var timeVar int
for {
if ping(ip) {
timeVar = 0
fmt.Println("Ping successful.")
} else {
timeVar++
fmt.Printf("Ping failed. time = %d\n", timeVar)
}
if timeVar >= 3 { // 连续 3 次 ping 失败,自动关机,根据自己需要修改
shutdown()
break
}
time.Sleep(10 * time.Second) // 10 秒 ping 一次,根据自己需要修改
}
}
GO(Linux)
// Linux 下关机需要提权
package main
import (
"fmt"
"os/exec"
"time"
)
func ping(ip string) bool {
cmd := exec.Command("ping", "-c", "1", ip)
err := cmd.Run()
return err == nil
}
func shutdown() {
cmd := exec.Command("shutdown", "-h", "now") // 其实就是关机命令和 Windows 不同
err := cmd.Run()
if err != nil {
fmt.Printf("Failed to shutdown: %v\n", err)
} else {
fmt.Println("Shutting down the system...")
}
}
func main() {
ip := "192.168.1.1" // 192.168.1.1 修改为监控机的实际 IP
var timeVar int
for {
if ping(ip) {
timeVar = 0
fmt.Println("Ping successful")
} else {
timeVar++
fmt.Printf("Ping failed. time = %d\n", timeVar)
}
if timeVar >= 3 { // 连续 3 次 ping 失败,自动关机,根据自己需要修改
shutdown()
break
}
time.Sleep(10 * time.Second) // 10 秒 ping 一次,根据自己需要修改
}
}
Java
// Linux 下关机需要提权
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Timer;
import java.util.TimerTask;
public class PingTask {
private static int time = 0;
public static void main(String[] args) {
Timer timer = new Timer();
TimerTask pingTask = new TimerTask() {
@Override
public void run() {
try {
Process process = Runtime.getRuntime().exec("ping -c 1 192.168.1.1"); // 192.168.1.1 修改为监控机的实际 IP
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
boolean isPingSuccess = false;
while ((line = reader.readLine()) != null) {
if (line.contains("1 received")) { // 1 received 为 Linux 下的 ping 返回内容,Windows 做对应更换就行
isPingSuccess = true;
break;
}
}
if (isPingSuccess) {
time = 0;
} else {
time++;
}
System.out.println("Current time: " + time);
if (time >= 3) { // 连续 3 次 ping 失败,自动关机,根据自己需要修改
System.out.println("Shutting down...");
Runtime.getRuntime().exec("systemctl poweroff");
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
timer.schedule(pingTask, 0, 10000); // 10 秒(10000 毫秒) ping 一次,根据自己需要修改
}
}
使用脚本
GO 的话可以直接编译成二进制使用;Java 的话需要有 Java 环境,搭建完成后可直接运行 .jar 文件,测试完没问题后加个开机自启就行。
Comments | NOTHING