feat:多跳(B->D->C->A)功能

This commit is contained in:
nnbcccscdscdsc
2026-03-27 23:03:00 +08:00
parent 5be3ff670f
commit 8e2bd0ffc6
8 changed files with 455 additions and 51 deletions

View File

@@ -5,6 +5,7 @@ import (
"log"
"net"
"strings"
"time"
kcp "github.com/xtaci/kcp-go/v5"
@@ -13,94 +14,124 @@ import (
"omnisocketgo/cmd/internal/transport"
)
const (
kcpServerModeHub = "hub"
kcpServerModeRelay = "relay"
)
func main() {
listenAddr := flag.String("listen", ":9002", "KCP server listen address")
mode := flag.String("mode", kcpServerModeHub, "kcpserver mode: hub or relay")
listenAddr := flag.String("listen", ":9002", "listen address; KCP listener in hub mode, UDP relay listener in relay mode")
bindDevice := flag.String("bind-device", "", "optional Linux network device used when listening")
logPath := flag.String("latency-log", "", "optional JSONL file path for latency timestamp logs")
kcpTimestampDebugLogPath := flag.String("kcp-ts-debug-log", "", "optional JSONL file path for KCP packet kernel timestamp debug records")
kcpSessionStatsLogPath := flag.String("kcp-session-stats-log", "", "optional JSONL file path for KCP session stats records")
kcpSessionStatsInterval := flag.String("kcp-session-stats-interval", transport.DefaultKCPSessionStatsInterval.String(), "sampling interval for KCP session stats, for example 100ms")
relayListenAddr := flag.String("relay-listen", "", "optional raw UDP relay listen address")
relayPeerAddr := flag.String("relay-peer", "", "optional fixed raw UDP relay peer address")
relayLearnPeer := flag.Bool("relay-learn-peer", false, "learn the relay peer address from the first inbound relay packet")
relayListenAddr := flag.String("relay-listen", "", "deprecated alias for -listen in relay mode")
relayRemoteAddr := flag.String("relay-remote", "", "fixed remote UDP address used in relay mode")
relayPeerAddr := flag.String("relay-peer", "", "deprecated alias for -relay-remote")
flag.Parse()
var relayRemoteFlagSet bool
var relayPeerFlagSet bool
var relayListenFlagSet bool
flag.Visit(func(f *flag.Flag) {
switch f.Name {
case "relay-listen":
relayListenFlagSet = true
case "relay-remote":
relayRemoteFlagSet = true
case "relay-peer":
relayPeerFlagSet = true
}
})
switch {
case relayRemoteFlagSet && relayPeerFlagSet && *relayRemoteAddr != *relayPeerAddr:
log.Fatal("flags -relay-remote and -relay-peer must match when both are set")
case *relayRemoteAddr == "" && *relayPeerAddr != "":
*relayRemoteAddr = *relayPeerAddr
}
if relayPeerFlagSet {
log.Printf("warning: flag -relay-peer is deprecated; use -relay-remote instead")
}
if relayListenFlagSet {
if *relayListenAddr == "" {
log.Fatal("flag -relay-listen must not be empty when set")
}
if *mode != kcpServerModeRelay {
log.Fatal("flag -relay-listen may only be used in relay mode")
}
if *listenAddr != ":9002" && *listenAddr != *relayListenAddr {
log.Fatal("flags -listen and -relay-listen must match when both are set in relay mode")
}
*listenAddr = *relayListenAddr
log.Printf("warning: flag -relay-listen is deprecated; use -listen with -mode=relay instead")
}
statsInterval, err := transport.ParseKCPSessionStatsInterval(*kcpSessionStatsInterval)
if err != nil {
log.Fatalf("parse -kcp-session-stats-interval=%q: %v", *kcpSessionStatsInterval, err)
}
switch *mode {
case kcpServerModeHub:
if *relayRemoteAddr != "" {
log.Fatal("flag -relay-remote may only be used in relay mode")
}
runHubServer(*listenAddr, *bindDevice, *logPath, *kcpTimestampDebugLogPath, *kcpSessionStatsLogPath, statsInterval)
case kcpServerModeRelay:
if *bindDevice != "" {
log.Fatal("flag -bind-device is not supported in relay mode")
}
if *relayRemoteAddr == "" {
log.Fatal("flag -relay-remote is required in relay mode")
}
runUDPRelayServer(*listenAddr, *relayRemoteAddr)
default:
log.Fatalf("unsupported -mode=%q; want %q or %q", *mode, kcpServerModeHub, kcpServerModeRelay)
}
}
func runHubServer(listenAddr, bindDevice, logPath, packetDebugLogPath, sessionStatsLogPath string, statsInterval time.Duration) {
hubOptions := make([]server.KCPOption, 0, 2)
if *logPath != "" {
logger, err := latencylog.NewJSONLLogger(*logPath)
if logPath != "" {
logger, err := latencylog.NewJSONLLogger(logPath)
if err != nil {
log.Fatalf("create latency logger %s: %v", *logPath, err)
log.Fatalf("create latency logger %s: %v", logPath, err)
}
defer logger.Close()
hubOptions = append(hubOptions, server.WithKCPLogger(logger))
}
var packetLogger transport.KCPPacketDebugLogger
if *kcpTimestampDebugLogPath != "" {
logger, err := transport.NewJSONLKCPPacketDebugLogger(*kcpTimestampDebugLogPath)
if packetDebugLogPath != "" {
logger, err := transport.NewJSONLKCPPacketDebugLogger(packetDebugLogPath)
if err != nil {
log.Fatalf("create kcp packet debug logger %s: %v", *kcpTimestampDebugLogPath, err)
log.Fatalf("create kcp packet debug logger %s: %v", packetDebugLogPath, err)
}
defer logger.Close()
packetLogger = logger
}
if *kcpSessionStatsLogPath != "" {
logger, err := transport.NewJSONLKCPSessionStatsLogger(*kcpSessionStatsLogPath)
if sessionStatsLogPath != "" {
logger, err := transport.NewJSONLKCPSessionStatsLogger(sessionStatsLogPath)
if err != nil {
log.Fatalf("create kcp session stats logger %s: %v", *kcpSessionStatsLogPath, err)
log.Fatalf("create kcp session stats logger %s: %v", sessionStatsLogPath, err)
}
defer logger.Close()
hubOptions = append(hubOptions, server.WithKCPSessionStatsLogger(logger, statsInterval))
}
listener, packetConn, err := transport.ListenKCPSessions(*listenAddr, *bindDevice, packetLogger, latencylog.NodeRoleServer, "hub")
listener, packetConn, err := transport.ListenKCPSessions(listenAddr, bindDevice, packetLogger, latencylog.NodeRoleServer, "hub")
if err != nil {
log.Fatalf("listen kcp on %s: %v", *listenAddr, err)
log.Fatalf("listen kcp on %s: %v", listenAddr, err)
}
defer packetConn.Close()
defer listener.Close()
hub := server.NewKCPHub(hubOptions...)
if *relayPeerAddr != "" && *relayListenAddr == "" {
log.Fatal("flag -relay-listen is required when -relay-peer is set")
}
if *relayLearnPeer && *relayListenAddr == "" {
log.Fatal("flag -relay-listen is required when -relay-learn-peer is set")
}
if *relayListenAddr != "" {
relayConn, err := net.ListenPacket("udp", *relayListenAddr)
if err != nil {
log.Fatalf("listen relay udp on %s: %v", *relayListenAddr, err)
}
defer relayConn.Close()
var relayPeer net.Addr
if *relayPeerAddr != "" {
relayPeer, err = net.ResolveUDPAddr("udp", *relayPeerAddr)
if err != nil {
log.Fatalf("resolve relay peer %s: %v", *relayPeerAddr, err)
}
}
hub.SetRelaySocket(relayConn, relayPeer, *relayLearnPeer)
go func() {
if serveErr := hub.ServeRelay(); serveErr != nil {
log.Printf("kcp relay loop ended: %v", serveErr)
}
}()
log.Printf("kcp relay listening on %s", relayConn.LocalAddr())
if relayPeer != nil {
log.Printf("kcp relay peer configured as %s", relayPeer)
}
}
log.Printf("kcp server listening on %s", listener.Addr())
log.Printf("kcp hub listening on %s", listener.Addr())
for {
session, err := listener.AcceptKCP()
@@ -119,3 +150,26 @@ func main() {
}(session)
}
}
func runUDPRelayServer(listenAddr, remoteAddr string) {
conn, err := net.ListenPacket("udp", listenAddr)
if err != nil {
log.Fatalf("listen udp relay on %s: %v", listenAddr, err)
}
defer conn.Close()
remote, err := net.ResolveUDPAddr("udp", remoteAddr)
if err != nil {
log.Fatalf("resolve relay remote %s: %v", remoteAddr, err)
}
relay, err := server.NewUDPRelay(conn, remote)
if err != nil {
log.Fatalf("create udp relay: %v", err)
}
log.Printf("udp relay listening on %s and forwarding to %s", conn.LocalAddr(), remote)
if err := relay.Serve(); err != nil {
log.Fatalf("udp relay stopped: %v", err)
}
}