Go 写一个小服务端跑在路由器上,外部经路由器访问,向局域网内的设备发送 Wake-on-LAN 魔术包。

1
go get -u github.com/gin-gonic/gin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package main

import (
"encoding/hex"
"fmt"
"log"
"net"
"strings"

"github.com/gin-gonic/gin"
)

// 发送 Wake-on-LAN 魔术包
func sendWOL(mac string, ip string, port int) error {
// 去掉分隔符
mac = strings.ReplaceAll(mac, ":", "")
mac = strings.ReplaceAll(mac, "-", "")
if len(mac) != 12 {
return fmt.Errorf("MAC 地址格式错误: %s", mac)
}

// 转换为二进制
macBytes, err := hex.DecodeString(mac)
if err != nil {
return fmt.Errorf("MAC 地址解码失败: %v", err)
}

// 构造魔术包
var packet []byte
packet = append(packet, []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}...)
for i := 0; i < 16; i++ {
packet = append(packet, macBytes...)
}

// 发送 UDP 包
addr := fmt.Sprintf("%s:%d", ip, port)
conn, err := net.Dial("udp", addr)
if err != nil {
return fmt.Errorf("UDP 连接失败: %v", err)
}
defer conn.Close()

_, err = conn.Write(packet)
if err != nil {
return fmt.Errorf("发送失败: %v", err)
}

return nil
}

func main() {
r := gin.Default()

r.GET("/wake/", func(c *gin.Context) {
mac := "FF-FF-FF-FF-FF-FF"
ip := "255.255.255.255"
port := 9

err := sendWOL(mac, ip, port)
if err != nil {
log.Printf("Wake-on-LAN 失败: %v", err)
c.String(500, "Wake-on-LAN 失败: %v", err)
return
}

c.String(200, "Wake-on-LAN packet sent")
})

r.Run("0.0.0.0:4514")
}