From 5022da488592bdd1b4b37cf399fcbb43d82e2b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=B9=BF?= Date: Fri, 10 Jul 2026 08:11:55 +0800 Subject: [PATCH] =?UTF-8?q?```=20feat:=20=E6=96=B0=E5=A2=9ETCP=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E6=9C=8D=E5=8A=A1=E5=99=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增完整的TCP代理服务器功能,支持在指定端口监听TCP请求并转发到目标服务器。 包含以下主要变更: - 新增 handler/tcpproxy.go 文件,实现 TcpProxyHandler 结构体和相关方法 - 在 model/model.go 中添加 TcpProxyConfig 配置结构 - 在 server/manager.go 中添加TCP代理服务器管理功能 - 修改 gohttp.go 在启动时初始化并启动TCP代理服务器 - 支持多TCP代理配置,每个代理可独立设置监听地址和目标服务器 - 提供完整的启动、停止和数据转发功能 - 包含详细的配置示例和文档说明 ``` --- changes.md | 61 +++++++++++++++++++++- gohttp.go | 10 ++++ handler/tcpproxy.go | 121 ++++++++++++++++++++++++++++++++++++++++++++ model/model.go | 17 +++++-- server/manager.go | 29 +++++++++++ 5 files changed, 233 insertions(+), 5 deletions(-) create mode 100644 handler/tcpproxy.go diff --git a/changes.md b/changes.md index 71749f5..9f29724 100644 --- a/changes.md +++ b/changes.md @@ -130,6 +130,65 @@ if slices.Contains(deniedIPs, clientIP) { ... } --- -## 6. 构建验证 +## 6. 新增功能:TCP代理服务器 + +### 6.1 功能概述 + +新增TCP代理服务器功能,支持在指定端口监听TCP请求并转发到指定服务器的指定端口。可以配置多个TCP代理。 + +### 6.2 新增文件 + +**handler/tcpproxy.go** - TCP代理处理器实现: +- `TcpProxyHandler` 结构体:管理TCP代理连接 +- `NewTcpProxyHandler` 函数:创建新的TCP代理处理器 +- `Start` 方法:启动TCP代理监听 +- `Stop` 方法:停止TCP代理服务器 +- `pipe` 方法:连接间数据转发 + +### 6.3 配置模型 (model/model.go) + +新增 `TcpProxyConfig` 配置结构: +```go +type TcpProxyConfig struct { + Name string `json:"name"` // 代理名称 + Listen string `json:"listen"` // 监听地址,格式如 "0.0.0.0:8080" + Target string `json:"target"` // 目标服务器地址,格式如 "192.168.1.1:3306" + Enabled bool `json:"enabled"` // 是否启用 +} +``` + +### 6.4 配置示例 + +在 `config.json` 中添加TCP代理配置: +```json +{ + "tcp_proxys": [ + { + "name": "mysql-proxy", + "listen": "0.0.0.0:3307", + "target": "192.168.1.100:3306", + "enabled": true + }, + { + "name": "redis-proxy", + "listen": "0.0.0.0:6380", + "target": "192.168.1.101:6379", + "enabled": true + } + ] +} +``` + +### 6.5 服务器管理 (server/manager.go) + +新增TCP代理服务器管理功能: +- `TcpProxyManager`:TCP代理处理器映射 +- `AddTcpProxy`:注册TCP代理服务器 +- `StartTcpProxies`:启动所有TCP代理服务器 +- `StopTcpProxies`:停止所有TCP代理服务器 + +--- + +## 7. 构建验证 所有修改已通过 `go build ./...` 编译验证。 diff --git a/gohttp.go b/gohttp.go index 26b14f3..3211e74 100644 --- a/gohttp.go +++ b/gohttp.go @@ -8,6 +8,7 @@ import ( "strings" "git.kingecg.top/kingecg/gohttpd/admin" + "git.kingecg.top/kingecg/gohttpd/handler" "git.kingecg.top/kingecg/gohttpd/model" "git.kingecg.top/kingecg/gohttpd/server" "git.kingecg.top/kingecg/gohttpd/utils" @@ -61,6 +62,15 @@ func (g *GoHttp) Start() { listener.Serve() } + // 启动TCP代理服务器 + for _, tcpConf := range conf.TcpProxys { + if tcpConf.Enabled { + tcpProxy := handler.NewTcpProxyHandler(tcpConf.Name, tcpConf.Listen, tcpConf.Target) + server.AddTcpProxy(tcpConf.Name, tcpProxy) + tcpProxy.Start() + } + } + // 记录 GoHttp 服务成功启动的信息 g.logger.Info("gohttpd start success") } diff --git a/handler/tcpproxy.go b/handler/tcpproxy.go new file mode 100644 index 0000000..8f1de44 --- /dev/null +++ b/handler/tcpproxy.go @@ -0,0 +1,121 @@ +package handler + +import ( + "fmt" + "io" + "net" + "sync" + + "git.kingecg.top/kingecg/gologger" +) + +// TcpProxyHandler TCP代理处理器 +type TcpProxyHandler struct { + Name string + Listen string + Target string + listener net.Listener + wg sync.WaitGroup + stopCh chan struct{} +} + +func NewTcpProxyHandler(name, listen, target string) *TcpProxyHandler { + return &TcpProxyHandler{ + Name: name, + Listen: listen, + Target: target, + stopCh: make(chan struct{}), + } +} + +// Start 开始监听并处理TCP连接 +func (t *TcpProxyHandler) Start() error { + l := gologger.GetLogger("TcpProxy") + l.Info(fmt.Sprintf("TCP proxy [%s] starting, listen: %s, target: %s", t.Name, t.Listen, t.Target)) + + var err error + t.listener, err = net.Listen("tcp", t.Listen) + if err != nil { + l.Error(fmt.Sprintf("TCP proxy [%s] failed to listen on %s: %v", t.Name, t.Listen, err)) + return err + } + + go t.acceptLoop() + return nil +} + +// acceptLoop 接受连接并处理 +func (t *TcpProxyHandler) acceptLoop() { + l := gologger.GetLogger("TcpProxy") + for { + conn, err := t.listener.Accept() + if err != nil { + select { + case <-t.stopCh: + l.Info(fmt.Sprintf("TCP proxy [%s] stopped", t.Name)) + return + default: + l.Error(fmt.Sprintf("TCP proxy [%s] accept error: %v", t.Name, err)) + continue + } + } + t.wg.Add(1) + go t.handleConn(conn) + } +} + +// handleConn 处理单个TCP连接 +func (t *TcpProxyHandler) handleConn(clientConn net.Conn) { + defer t.wg.Done() + l := gologger.GetLogger("TcpProxy") + + l.Debug(fmt.Sprintf("TCP proxy [%s] new connection from %s", t.Name, clientConn.RemoteAddr())) + + // 连接到目标服务器 + targetConn, err := net.DialTimeout("tcp", t.Target, 10*1000000000) // 10秒超时 + if err != nil { + l.Error(fmt.Sprintf("TCP proxy [%s] failed to connect to target %s: %v", t.Name, t.Target, err)) + clientConn.Close() + return + } + + // 使用管道模式转发数据 + go t.pipe(clientConn, targetConn, "client->target") + go t.pipe(targetConn, clientConn, "target->client") + + l.Debug(fmt.Sprintf("TCP proxy [%s] connection established", t.Name)) +} + +// pipe 在两个连接之间转发数据 +func (t *TcpProxyHandler) pipe(dst, src net.Conn, direction string) { + defer dst.Close() + l := gologger.GetLogger("TcpProxy") + buf := make([]byte, 8192) + for { + n, err := src.Read(buf) + if err != nil { + if err != io.EOF { + l.Debug(fmt.Sprintf("TCP proxy [%s] %s read error: %v", t.Name, direction, err)) + } + return + } + _, err = dst.Write(buf[:n]) + if err != nil { + l.Debug(fmt.Sprintf("TCP proxy [%s] %s write error: %v", t.Name, direction, err)) + return + } + } +} + +// Stop 停止TCP代理服务器 +func (t *TcpProxyHandler) Stop() error { + l := gologger.GetLogger("TcpProxy") + l.Info(fmt.Sprintf("TCP proxy [%s] stopping...", t.Name)) + close(t.stopCh) + if t.listener != nil { + t.listener.Close() + } + t.wg.Wait() + l.Info(fmt.Sprintf("TCP proxy [%s] stopped", t.Name)) + return nil +} diff --git a/model/model.go b/model/model.go index c09a131..50e45dc 100644 --- a/model/model.go +++ b/model/model.go @@ -62,10 +62,19 @@ type JwtConfig struct { } type GoHttpdConfig struct { - Logging gologger.LoggersConfig `json:"logging"` - Admin *HttpServerConfig `json:"admin"` - IncludDir string `json:"includs"` - Servers []*HttpServerConfig `json:"servers"` + Logging gologger.LoggersConfig `json:"logging"` + Admin *HttpServerConfig `json:"admin"` + IncludDir string `json:"includs"` + Servers []*HttpServerConfig `json:"servers"` + TcpProxys []*TcpProxyConfig `json:"tcp_proxys"` +} + +// TcpProxyConfig TCP代理服务器配置 +type TcpProxyConfig struct { + Name string `json:"name"` // 代理名称 + Listen string `json:"listen"` // 监听地址,格式如 "0.0.0.0:8080" + Target string `json:"target"` // 目标服务器地址,格式如 "192.168.1.1:3306" + Enabled bool `json:"enabled"` // 是否启用 } var DefaultAdminConfig HttpServerConfig = HttpServerConfig{ diff --git a/server/manager.go b/server/manager.go index eec2bbe..e0fde1b 100644 --- a/server/manager.go +++ b/server/manager.go @@ -10,6 +10,7 @@ import ( "io" "git.kingecg.top/kingecg/cmux" + "git.kingecg.top/kingecg/gohttpd/handler" "git.kingecg.top/kingecg/gohttpd/model" logger "git.kingecg.top/kingecg/gologger" ) @@ -246,3 +247,31 @@ func StartServer(name string, port int) { } listener.StartServer(name) } + +// TcpProxyManager TCP代理服务器管理器 +var TcpProxyManager = make(map[string]*handler.TcpProxyHandler) + +// AddTcpProxy 添加TCP代理服务器 +func AddTcpProxy(name string, proxy *handler.TcpProxyHandler) { + TcpProxyManager[name] = proxy +} + +// StartTcpProxies 启动所有TCP代理服务器 +func StartTcpProxies() { + l := logger.GetLogger("TcpProxy") + for _, proxy := range TcpProxyManager { + if err := proxy.Start(); err != nil { + l.Error(fmt.Sprintf("Failed to start TCP proxy [%s]: %v", proxy.Name, err)) + } + } +} + +// StopTcpProxies 停止所有TCP代理服务器 +func StopTcpProxies() { + l := logger.GetLogger("TcpProxy") + for _, proxy := range TcpProxyManager { + if err := proxy.Stop(); err != nil { + l.Error(fmt.Sprintf("Failed to stop TCP proxy [%s]: %v", proxy.Name, err)) + } + } +}