```
feat: 新增TCP代理服务器功能 新增完整的TCP代理服务器功能,支持在指定端口监听TCP请求并转发到目标服务器。 包含以下主要变更: - 新增 handler/tcpproxy.go 文件,实现 TcpProxyHandler 结构体和相关方法 - 在 model/model.go 中添加 TcpProxyConfig 配置结构 - 在 server/manager.go 中添加TCP代理服务器管理功能 - 修改 gohttp.go 在启动时初始化并启动TCP代理服务器 - 支持多TCP代理配置,每个代理可独立设置监听地址和目标服务器 - 提供完整的启动、停止和数据转发功能 - 包含详细的配置示例和文档说明 ```
This commit is contained in:
parent
5e09b26261
commit
5022da4885
61
changes.md
61
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 ./...` 编译验证。
|
所有修改已通过 `go build ./...` 编译验证。
|
||||||
|
|
|
||||||
10
gohttp.go
10
gohttp.go
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.kingecg.top/kingecg/gohttpd/admin"
|
"git.kingecg.top/kingecg/gohttpd/admin"
|
||||||
|
"git.kingecg.top/kingecg/gohttpd/handler"
|
||||||
"git.kingecg.top/kingecg/gohttpd/model"
|
"git.kingecg.top/kingecg/gohttpd/model"
|
||||||
"git.kingecg.top/kingecg/gohttpd/server"
|
"git.kingecg.top/kingecg/gohttpd/server"
|
||||||
"git.kingecg.top/kingecg/gohttpd/utils"
|
"git.kingecg.top/kingecg/gohttpd/utils"
|
||||||
|
|
@ -61,6 +62,15 @@ func (g *GoHttp) Start() {
|
||||||
listener.Serve()
|
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 服务成功启动的信息
|
// 记录 GoHttp 服务成功启动的信息
|
||||||
g.logger.Info("gohttpd start success")
|
g.logger.Info("gohttpd start success")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -62,10 +62,19 @@ type JwtConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type GoHttpdConfig struct {
|
type GoHttpdConfig struct {
|
||||||
Logging gologger.LoggersConfig `json:"logging"`
|
Logging gologger.LoggersConfig `json:"logging"`
|
||||||
Admin *HttpServerConfig `json:"admin"`
|
Admin *HttpServerConfig `json:"admin"`
|
||||||
IncludDir string `json:"includs"`
|
IncludDir string `json:"includs"`
|
||||||
Servers []*HttpServerConfig `json:"servers"`
|
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{
|
var DefaultAdminConfig HttpServerConfig = HttpServerConfig{
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.kingecg.top/kingecg/cmux"
|
"git.kingecg.top/kingecg/cmux"
|
||||||
|
"git.kingecg.top/kingecg/gohttpd/handler"
|
||||||
"git.kingecg.top/kingecg/gohttpd/model"
|
"git.kingecg.top/kingecg/gohttpd/model"
|
||||||
logger "git.kingecg.top/kingecg/gologger"
|
logger "git.kingecg.top/kingecg/gologger"
|
||||||
)
|
)
|
||||||
|
|
@ -246,3 +247,31 @@ func StartServer(name string, port int) {
|
||||||
}
|
}
|
||||||
listener.StartServer(name)
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue