# goproxy **Repository Path**: cutecuteyu/goproxy ## Basic Information - **Project Name**: goproxy - **Description**: go编写的支持http和tcp切换的端口转发工具 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-10-26 - **Last Updated**: 2025-12-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # GoProxy - HTTP/TCP 代理转发工具 一个用 Go 语言编写的高性能、企业级的代理转发工具,支持 HTTP 和 TCP 协议。 ## ✨ 特性 - 🚀 **高性能** - 预创建代理对象,避免重复创建,提升处理效率 - 🔒 **稳定可靠** - 修复连接泄漏,添加超时控制,确保资源正确释放 - 🛡️ **生产就绪** - 支持优雅关闭、连接数限制、多级日志系统 - ⚙️ **灵活配置** - 通过配置文件轻松管理所有参数 - 📊 **可观测性** - 详细的日志记录,支持 DEBUG/INFO/WARN/ERROR 四个级别 ## 📦 安装 ### 从源码构建 ```bash # 克隆仓库 git clone https://gitee.com/cutecuteyu/goproxy cd goproxy # 初始化 Go 模块 go mod init goproxy # 安装依赖 go mod tidy # 编译(推荐使用编译优化参数) go build -ldflags="-s -w" -o goproxy.exe # 或者不使用优化参数(适合调试) go build -o goproxy.exe ``` ### Go 依赖 ``` require gopkg.in/ini.v1 v1.67.0 ``` ## 🚀 快速开始 ### 1. 配置 config.ini 编辑 `config.ini` 文件,设置目标服务器和协议类型: ```ini [server] # 目标服务器地址 target = http://192.168.101.104:4444 # 协议类型: http 或 tcp protocol = http # 监听端口(本代理服务器监听的端口) port = 8080 # 最大并发连接数(仅对 TCP 代理有效) max_connections = 1000 # 日志级别: DEBUG, INFO, WARN, ERROR log_level = INFO ``` ### 2. 运行程序 **Windows:** ```bash # 直接运行 goproxy.exe # 或使用 go run go run main.go ``` **Linux/Mac:** ```bash # 直接运行 ./goproxy # 或使用 go run go run main.go ``` ### 3. 测试代理 **HTTP 代理测试:** ```bash curl http://localhost:8080/api/test ``` **TCP 代理测试:** ```bash telnet localhost 8080 # 然后输入要发送到目标服务器的数据 ``` ## ⚙️ 配置说明 ### 配置项详解 | 配置项 | 类型 | 必填 | 默认值 | 说明 | |--------|------|------|--------|------| | `target` | string | ✅ | - | 目标服务器地址 | | `protocol` | string | ✅ | - | 协议类型:`http` 或 `tcp` | | `port` | string | ❌ | 8080 | 代理服务器监听端口 | | `max_connections` | int | ❌ | 1000 | 最大并发连接数(仅 TCP) | | `log_level` | string | ❌ | INFO | 日志级别:`DEBUG`/`INFO`/`WARN`/`ERROR` | ### HTTP 代理配置示例 ```ini [server] # HTTP 代理需要完整的 URL target = http://example.com protocol = http port = 8888 log_level = INFO ``` ### TCP 代理配置示例 ```ini [server] # TCP 代理直接写 IP:端口 target = 192.168.1.4:7860 protocol = tcp port = 8080 max_connections = 1000 log_level = INFO ``` ## 📊 日志系统 ### 日志级别说明 - **DEBUG** - 显示所有详细日志(包括每个连接、传输字节数等) ``` [DEBUG] 成功建立TCP连接 [客户端: 127.0.0.1:12345 -> 目标: 192.168.1.4:7860] [DEBUG] 客户端到目标服务器数据传输完成 [传输: 1024 bytes] ``` - **INFO** - 显示一般信息(启动、关闭等) ``` [INFO] 配置加载成功 - 端口: 8080, 目标: http://example.com, 协议: http [INFO] HTTP代理正在监听端口 8080 并转发到 http://example.com ``` - **WARN** - 只显示警告和错误 ``` [WARN] 连接数已达上限 1000,拒绝新连接来自 192.168.1.100:54321 [WARN] 客户端到目标服务器数据转发错误 [已传输: 512 bytes]: EOF ``` - **ERROR** - 只显示错误信息 ``` [ERROR] 连接目标服务器错误 [目标: 192.168.1.4:7860]: dial tcp 192.168.1.4:7860: connect: connection refused ``` ### 生产环境建议 ```ini # 开发环境:使用 DEBUG 级别查看详细信息 log_level = DEBUG # 测试环境:使用 INFO 级别 log_level = INFO # 生产环境:使用 WARN 级别减少日志量 log_level = WARN ``` ## 🔧 高级功能 ### 优雅关闭 程序支持优雅关闭,当收到 `Ctrl+C` 或 `SIGTERM` 信号时: - 等待现有请求处理完成(最多等待 5 秒) - 关闭监听端口,不再接受新连接 - 等待所有 TCP 连接处理完成 - 退出程序 ```bash # 按 Ctrl+C 触发优雅关闭 ^C [INFO] 接收到信号: interrupt,开始优雅关闭... [INFO] 正在关闭HTTP代理服务器... [INFO] HTTP代理服务器已关闭 ``` ### 连接数限制 TCP 代理支持最大连接数限制,防止资源耗尽: ```ini max_connections = 1000 # 最大 1000 个并发连接 ``` 当连接数达到上限时,会拒绝新连接并记录警告日志: ``` [WARN] 连接数已达上限 1000,拒绝新连接来自 192.168.1.100:54321 ``` ### 超时控制 TCP 代理内置超时控制: - **连接超时**:30 秒内必须建立连接 - **目标连接超时**:5 秒内必须连接到目标服务器 - **数据传输**:连接成功后无超时限制 ## 🎯 使用场景 ### 1. 本地开发代理 将本地请求转发到远程服务器: ```ini [server] target = http://api.production-server.com protocol = http port = 3000 log_level = DEBUG ``` 访问 `http://localhost:3000` 即可转发到生产服务器。 ### 2. 端口转发 转发本地端口到远程服务器: ```ini [server] target = 192.168.1.100:3306 protocol = tcp port = 3306 max_connections = 100 log_level = INFO ``` 连接 `localhost:3306` 即可连接到远程 MySQL 服务器。 ### 3. 负载均衡 运行多个代理实例: ```bash # 实例 1:监听 8080 # 实例 2:监听 8081 # 实例 3:监听 8082 ``` 然后使用 Nginx 或其他负载均衡器分发请求。 ## 🛠️ 故障排查 ### 常见问题 **1. 端口已被占用** ``` [FATAL] 监听端口错误: listen tcp :8080: bind: address already in use ``` **解决方案**:修改 `config.ini` 中的 `port` 配置,使用其他端口。 **2. 无法连接到目标服务器** ``` [ERROR] 连接目标服务器错误 [目标: 192.168.1.4:7860]: dial tcp 192.168.1.4:7860: connect: connection refused ``` **解决方案**: - 检查目标服务器地址是否正确 - 确认目标服务器正在运行 - 检查网络连接和防火墙设置 **3. 配置文件错误** ``` [FATAL] 配置错误: 目标服务器地址 (target) 不能为空 ``` **解决方案**:检查 `config.ini` 文件,确保所有必填项都已填写。 **4. 连接数过多** ``` [WARN] 连接数已达上限 1000,拒绝新连接来自 192.168.1.100:54321 ``` **解决方案**:增加 `max_connections` 的值。 ## 📝 开发说明 ### 项目结构 ``` goproxy/ ├── main.go # 主程序入口(57 行) ├── config.ini # 配置文件 ├── go.mod # Go 模块定义 ├── README.md # 项目文档 ├── logger/ # 日志模块 │ └── logger.go # 日志记录器实现(60 行) ├── config/ # 配置模块 │ └── config.go # 配置加载和验证(56 行) └── proxy/ # 代理模块 └── proxy.go # HTTP/TCP 代理实现(166 行) ``` ### 🧩 模块说明 #### 1. **logger 模块** (`logger/logger.go`) **职责:** 提供带级别的日志记录功能 **导出类型和函数:** - `LogLevel` - 日志级别类型(DEBUG, INFO, WARN, ERROR) - `Logger` - 日志记录器结构体 - `New(level string) *Logger` - 创建新的日志记录器 - `Debug(format, ...interface{})` - 调试日志 - `Info(format, ...interface{})` - 信息日志 - `Warn(format, ...interface{})` - 警告日志 - `Error(format, ...interface{})` - 错误日志 - `Fatal(format, ...interface{})` - 致命错误日志 **使用示例:** ```go import "goproxy/logger" log := logger.New("INFO") log.Info("服务器启动成功") log.Error("连接失败: %v", err) ``` #### 2. **config 模块** (`config/config.go`) **职责:** 配置文件的加载、解析和验证 **导出类型和函数:** - `Config` - 配置结构体(包含 LogLevel, Port, Target, Protocol, MaxConnections) - `Load(cfgFile string, log *logger.Logger) (*Config, error)` - 加载配置文件 - `Validate(log *logger.Logger) error` - 验证配置 **使用示例:** ```go import "goproxy/config" cfg, err := config.Load("config.ini", logger) if err != nil { log.Fatalf("配置加载失败: %v", err) } ``` #### 3. **proxy 模块** (`proxy/proxy.go`) **职责:** HTTP 和 TCP 代理服务器的实现 **导出函数:** - `RunHTTP(ctx, target, port, log)` - 运行 HTTP 代理服务器 - `RunTCP(ctx, target, port, connSem, log)` - 运行 TCP 代理服务器 **使用示例:** ```go import "goproxy/proxy" // HTTP 代理 proxy.RunHTTP(ctx, cfg.Target, cfg.Port, logger) // TCP 代理 connSem := make(chan struct{}, cfg.MaxConnections) proxy.RunTCP(ctx, cfg.Target, cfg.Port, connSem, logger) ``` #### 4. **main 模块** (`main.go`) **职责:** 程序入口,协调各个模块 **主要流程:** 1. 创建临时日志记录器 2. 加载配置文件 3. 创建最终的日志记录器 4. 创建连接数限制信号量 5. 设置信号处理器(优雅关闭) 6. 启动代理服务器 ### 🔄 模块依赖关系 ``` main.go ├─→ config ──→ logger ├─→ logger └─→ proxy ──→ logger ``` **依赖说明:** - `main` 依赖所有模块 - `config` 依赖 `logger`(用于配置验证时的日志输出) - `proxy` 依赖 `logger`(用于代理运行时的日志记录) - `logger` 是基础模块,不依赖其他模块 ### 📊 代码重构对比 **重构前(单文件):** - 文件数量:1 个(main.go) - 代码行数:329 行 - 所有代码混在一个文件中 **重构后(模块化):** - 文件数量:4 个(main.go + 3 个模块) - 代码行数:339 行(main.go: 57 行,logger.go: 60 行,config.go: 56 行,proxy.go: 166 行) - 职责分离,每个模块功能单一 **模块化优势:** - ✅ 易于测试(可单独测试每个模块) - ✅ 易于维护(修改某个模块不影响其他模块) - ✅ 代码复用(模块可在其他项目中使用) - ✅ 团队协作(不同人员可并行开发不同模块) ### 🧪 测试建议 由于代码已模块化,现在可以轻松地为每个模块编写单元测试: #### logger 模块测试 ```go // logger/logger_test.go func TestNewLogger(t *testing.T) { log := logger.New("DEBUG") // 测试日志级别设置 } ``` #### config 模块测试 ```go // config/config_test.go func TestLoadConfig(t *testing.T) { // 测试配置加载 // 测试配置验证 } ``` #### proxy 模块测试 ```go // proxy/proxy_test.go func TestHandleTCPConnection(t *testing.T) { // 测试 TCP 连接处理 } ``` ### 📝 扩展建议 基于当前的模块化结构,可以轻松扩展功能: #### 1. 添加 metrics 模块 ```go // metrics/metrics.go package metrics type Metrics struct { Connections int64 BytesSent int64 BytesReceived int64 } func (m *Metrics) IncrementConnections() func (m *Metrics) AddBytesSent(n int64) ``` #### 2. 添加 auth 模块 ```go // auth/auth.go package auth type Authenticator interface { Authenticate(username, password string) bool } ``` #### 3. 添加 health 模块 ```go // health/health.go package health func Check(target string) error ``` ### 代码优化记录 本项目经过全面优化,解决了以下问题: **高优先级修复:** - ✅ HTTP 代理对象重复创建 → 预创建复用 - ✅ TCP 连接泄漏 → channel 同步机制 - ✅ 配置验证缺失 → 完整的配置验证 **中优先级修复:** - ✅ 优雅关闭缺失 → SIGINT/SIGTERM 信号处理 - ✅ 硬编码端口号 → 可配置端口 - ✅ 错误处理不完整 → 增强错误日志和超时控制 **低优先级修复:** - ✅ 无连接数限制 → 信号量机制限制连接 - ✅ 简单日志系统 → 四级日志系统 - ✅ 代码结构混乱 → 模块化重构 ### 🎯 模块化重构总结 **重构带来的好处:** 1. **可维护性提升** ⬆️ - 每个模块职责单一 - 代码组织清晰 - 易于定位和修复问题 2. **可测试性提升** ⬆️ - 可独立测试每个模块 - 便于编写单元测试 - 提高代码质量 3. **可扩展性提升** ⬆️ - 新增功能不影响现有代码 - 可轻松添加新模块 - 支持插件化架构 4. **团队协作提升** ⬆️ - 不同人员可并行开发 - 减少代码冲突 - 提高开发效率 5. **编译选项不变** ✅ - 保持原有的编译命令 - 不影响部署流程 - 无缝迁移到模块化架构 ## 📄 许可证 本项目采用 MIT 许可证。 ## 🤝 贡献 欢迎提交 Issue 和 Pull Request! ## 📮 联系方式 如有问题或建议,请提交 Issue。