欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > 高效 TCP 代理服务器的实战解析:Go 语言编写的高性能代理实例20241028

高效 TCP 代理服务器的实战解析:Go 语言编写的高性能代理实例20241028

2025/1/3 10:38:17 来源:https://blog.csdn.net/Narutolxy/article/details/143303972  浏览:    关键词:高效 TCP 代理服务器的实战解析:Go 语言编写的高性能代理实例20241028

高效 TCP 代理服务器的实战解析:Go 语言编写的高性能代理实例

引言

Go 语言天然支持并发处理,因此在高性能网络服务和代理服务开发中颇具优势。本文将从配置、并发控制、日志记录和优雅关机等方面,深入解读一个基于 Go 的 TCP 代理服务器项目。希望通过这个实战项目,帮助读者更好地理解 Go 语言在构建高性能应用时的应用场景与技巧。


目录结构

在项目目录结构设计上,我们保持文件的简洁性,并通过 Makefile.gitignore 管理构建过程和版本控制:

go-tcp-proxy/
├── go_tcp_proxy.go                # 主程序文件
├── config.json                    # 配置文件
├── Makefile                       # 构建和运行自动化
├── README.md                      # 项目说明文档
└── .gitignore                     # Git忽略规则

通过 .gitignore 文件,我们可以忽略编译后的二进制文件和配置文件:

# 忽略二进制文件
go-tcp-proxy
*.exe# 配置文件(如需私有配置)
config.json

Makefile 文件可以帮助我们简化编译和运行过程,内容如下:

APP_NAME := go-tcp-proxy.PHONY: all build clean runall: build runbuild:@echo "==> Building $(APP_NAME)..."@go build -o $(APP_NAME) go_tcp_proxy.goclean:@echo "==> Cleaning up..."@rm -f $(APP_NAME)run:@echo "==> Running $(APP_NAME)..."./$(APP_NAME)

代码实现解析

以下是 go_tcp_proxy.go 的完整代码,包含详细注释:

package mainimport ("encoding/json""fmt""io""log""net""os""os/signal""path/filepath""strings""sync""syscall""time"
)// Config 配置结构体定义
type Config struct {ListenPort    int    `json:"listen_port"`TargetHost    string `json:"target_host"`TargetPort    int    `json:"target_port"`RequestDelay  int    `json:"request_delay"`ResponseDelay int    `json:"response_delay"`LogLevel      string `json:"log_level"`
}// 全局变量
var (maxConcurrentConnections = 20                        // 最大并发连接数semaphore                = make(chan struct{}, maxConcurrentConnections) // 控制并发连接的信号量configMutex              sync.Mutex                  // 保护配置的锁currentConfig            Config                      // 当前加载的配置
)// 配置文件路径
func getConfigPath() string {homeDir, err := os.UserHomeDir()if err != nil {log.Fatal(err)}return filepath.Join(homeDir, "etc", "config.json")
}// 加载配置
func loadConfig() Config {configPath := getConfigPath()file, err := os.Open(configPath)if err != nil {logError("加载配置失败: %v", err)return currentConfig}defer file.Close()var config Configdecoder := json.NewDecoder(file)err = decoder.Decode(&config)if err != nil {logError("配置解析失败: %v", err)return currentConfig}// 默认日志级别为 "info"if config.LogLevel == "" {config.LogLevel = "info"}logInfo("成功加载配置: %+v", config)return config
}// 日志控制函数
func logInfo(format string, v ...interface{}) {if currentConfig.LogLevel == "info" || currentConfig.LogLevel == "debug" {log.Printf("[INFO] "+format, v...)}
}func logDebug(format string, v ...interface{}) {if currentConfig.LogLevel == "debug" {log.Printf("[DEBUG] "+format, v...)}
}func logError(format string, v ...interface{}) {if currentConfig.LogLevel == "error" || currentConfig.LogLevel == "info" || currentConfig.LogLevel == "debug" {log.Printf("[ERROR] "+format, v...)}
}func logFatal(format string, v ...interface{}) {log.Fatalf("[FATAL] "+format, v...)
}// 处理客户端连接
func handleConnection(clientConn net.Conn) {defer clientConn.Close()logInfo("客户端 %v 已连接", clientConn.RemoteAddr())// 控制并发连接数量semaphore <- struct{}{}defer func() { <-semaphore }()// 加载延迟设置configMutex.Lock()requestDelay := time.Duration(currentConfig.RequestDelay) * time.SecondresponseDelay := time.Duration(currentConfig.ResponseDelay) * time.SecondconfigMutex.Unlock()// 请求延迟处理if requestDelay > 0 {logInfo("请求延迟: %v 秒", requestDelay.Seconds())time.Sleep(requestDelay)}// 连接目标服务器targetConn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", currentConfig.TargetHost, currentConfig.TargetPort))if err != nil {logError("连接目标服务器失败: %v", err)return}defer func() {logInfo("关闭与目标服务器 %v 的连接", targetConn.RemoteAddr())targetConn.Close()}()logInfo("成功连接到目标服务器 %s:%d", currentConfig.TargetHost, currentConfig.TargetPort)// 双向数据转发go forwardData(targetConn, clientConn, responseDelay) // 从目标到客户端forwardData(clientConn, targetConn, 0)                // 从客户端到目标logInfo("客户端 %v 的连接已关闭", clientConn.RemoteAddr())
}// 数据转发函数
func forwardData(source, destination net.Conn, delay time.Duration) {buffer := make([]byte, 4096)for {n, err := source.Read(buffer)if n > 0 {if delay > 0 {logDebug("响应延迟: %v", delay)time.Sleep(delay)}_, writeErr := destination.Write(buffer[:n])if writeErr != nil {logError("数据写入目标连接失败: %v", writeErr)break}logDebug("成功转发数据 %d 字节", n)}if err != nil {if err != io.EOF && !strings.Contains(err.Error(), "use of closed network connection") {logError("数据转发异常: %v", err)}break}}
}// 优雅关机函数
func gracefulShutdown(listener net.Listener, done chan bool, exit chan bool) {c := make(chan os.Signal, 1)signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)<-clogInfo("正在关闭服务器...")listener.Close()done <- trueexit <- true
}// 主函数
func main() {currentConfig = loadConfig()listenAddr := fmt.Sprintf(":%d", currentConfig.ListenPort)// 启动监听器listener, err := net.Listen("tcp", listenAddr)if err != nil {logFatal("监听失败: %v", err)}defer listener.Close()logInfo("代理服务器监听端口 %d,最大并发连接数为 %d", currentConfig.ListenPort, maxConcurrentConnections)// 优雅退出通道done := make(chan bool)exit := make(chan bool)go gracefulShutdown(listener, done, exit)for {select {case <-done:logInfo("服务器已成功关闭.")returndefault:clientConn, err := listener.Accept()if err != nil {select {case <-exit:returndefault:logError("接受连接失败: %v", err)}continue}go handleConnection(clientConn)}}
}

总结

通过这份完整的代码及其深入解析,我们可以了解到构建一个稳定、高效的 TCP 代理服务的基本要素。本文代码实现展示了 Go 语言在并发编程和网络编程方面的强大能力。特别是在项目中:

  1. 多级别日志系统:通过 InfoDebugError 级别的日志管理,可以在开发和生产环境中灵活控制日志量。
  2. 高效的并发控制:通过信号量实现的连接限制,能够有效避免过多连接造成的系统压力。
  3. 优雅退出:通过系统信号捕获,实现了服务的优雅关机,确保资源得以释放。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com