first commit!
This commit is contained in:
commit
43f61be8b8
|
|
@ -0,0 +1,2 @@
|
|||
pip install pyinstaller
|
||||
pyinstaller --onefile src/linux_udp_client.py
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, GLib
|
||||
|
||||
import socket
|
||||
import json
|
||||
import threading
|
||||
import webbrowser
|
||||
|
||||
UDP_PORT = 9876
|
||||
|
||||
class UDPClient(Gtk.Window):
|
||||
def __init__(self):
|
||||
super().__init__(title="AI服务器发现工具")
|
||||
self.set_border_width(20)
|
||||
self.set_default_size(400, 150)
|
||||
|
||||
self.label = Gtk.Label(label="监听中... 请确保 AI 服务器在线")
|
||||
self.add(self.label)
|
||||
|
||||
self.popup_shown = False # 每次启动只弹一次
|
||||
|
||||
threading.Thread(target=self.listen_udp, daemon=True).start()
|
||||
|
||||
def listen_udp(self):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind(("", UDP_PORT))
|
||||
print(f"Listening on UDP port {UDP_PORT}...")
|
||||
|
||||
while True:
|
||||
data, addr = sock.recvfrom(1024)
|
||||
try:
|
||||
msg = json.loads(data.decode("utf-8"))
|
||||
if msg.get("type") == "ai_server_announce":
|
||||
ip = msg.get("ip")
|
||||
name = msg.get("name", "Unknown")
|
||||
url = f"http://{ip}:80" # 明确指定80端口
|
||||
|
||||
if not self.popup_shown:
|
||||
self.popup_shown = True
|
||||
GLib.idle_add(self.update_ui, name, url)
|
||||
|
||||
except Exception as e:
|
||||
print("Error parsing message:", e)
|
||||
|
||||
def update_ui(self, name, url):
|
||||
self.label.set_text(f"发现设备:{name}\n{url}")
|
||||
dialog = Gtk.MessageDialog(
|
||||
transient_for=self,
|
||||
flags=0,
|
||||
message_type=Gtk.MessageType.QUESTION,
|
||||
buttons=Gtk.ButtonsType.YES_NO,
|
||||
text="是否访问 AI 服务器?",
|
||||
)
|
||||
dialog.format_secondary_text(url)
|
||||
response = dialog.run()
|
||||
dialog.destroy()
|
||||
|
||||
if response == Gtk.ResponseType.YES:
|
||||
webbrowser.open(url)
|
||||
|
||||
return False
|
||||
|
||||
def main():
|
||||
app = UDPClient()
|
||||
app.connect("destroy", Gtk.main_quit)
|
||||
app.show_all()
|
||||
Gtk.main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,140 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BroadcastMessage struct {
|
||||
Type string `json:"type"`
|
||||
IP string `json:"ip"`
|
||||
Port int `json:"port"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func getGatewayIP() (string, error) {
|
||||
var cmd *exec.Cmd
|
||||
if runtime.GOOS == "linux" {
|
||||
cmd = exec.Command("sh", "-c", "ip route | grep default | awk '{print $3}'")
|
||||
} else if runtime.GOOS == "darwin" {
|
||||
cmd = exec.Command("sh", "-c", "netstat -rn | grep default | awk '{print $2}'")
|
||||
} else {
|
||||
return "", fmt.Errorf("unsupported OS")
|
||||
}
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
}
|
||||
|
||||
func ipInSameSubnet(ip1 net.IP, ip2 net.IP, mask net.IPMask) bool {
|
||||
if mask == nil {
|
||||
return false
|
||||
}
|
||||
net1 := ip1.Mask(mask)
|
||||
net2 := ip2.Mask(mask)
|
||||
return net1.Equal(net2)
|
||||
}
|
||||
|
||||
func getLocalIP() string {
|
||||
gatewayStr, err := getGatewayIP()
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get gateway IP:", err)
|
||||
return "127.0.0.1"
|
||||
}
|
||||
gateway := net.ParseIP(gatewayStr)
|
||||
if gateway == nil {
|
||||
fmt.Println("Invalid gateway IP")
|
||||
return "127.0.0.1"
|
||||
}
|
||||
|
||||
interfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
fmt.Println("Failed to get network interfaces:", err)
|
||||
return "127.0.0.1"
|
||||
}
|
||||
|
||||
for _, iface := range interfaces {
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
continue // interface down
|
||||
}
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
var mask net.IPMask
|
||||
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
mask = v.Mask
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
|
||||
if ip == nil || ip.IsLoopback() || ip.To4() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if ipInSameSubnet(ip, gateway, mask) {
|
||||
return ip.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
return "127.0.0.1"
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 参数
|
||||
var (
|
||||
port = flag.Int("port", 8000, "Device service port")
|
||||
interval = flag.Int("interval", 2, "Broadcast interval in seconds")
|
||||
name = flag.String("name", "My-AI-Server", "Device name")
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
ip := getLocalIP()
|
||||
if ip == "127.0.0.1" {
|
||||
fmt.Println("Warning: failed to find suitable IP address, using loopback")
|
||||
}
|
||||
|
||||
addr := net.UDPAddr{
|
||||
IP: net.IPv4bcast,
|
||||
Port: 9876,
|
||||
}
|
||||
conn, err := net.DialUDP("udp4", nil, &addr)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to dial UDP broadcast:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
for {
|
||||
msg := BroadcastMessage{
|
||||
Type: "ai_server_announce",
|
||||
IP: ip,
|
||||
Port: *port,
|
||||
Name: *name,
|
||||
}
|
||||
data, _ := json.Marshal(msg)
|
||||
_, err := conn.Write(data)
|
||||
if err != nil {
|
||||
fmt.Println("Broadcast failed:", err)
|
||||
} else {
|
||||
fmt.Printf("Broadcasted: %s:%d (%s)\n", ip, *port, *name)
|
||||
}
|
||||
time.Sleep(time.Duration(*interval) * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# Linux/macOS
|
||||
go build -o broadcaster broadcaster.go
|
||||
./broadcaster -port=9876 -interval=2 -name="T1-GRT309024X2"
|
||||
|
||||
Loading…
Reference in New Issue