diff --git a/internal/server/http.go b/internal/server/http.go index 40b120a..6607de7 100644 --- a/internal/server/http.go +++ b/internal/server/http.go @@ -3,7 +3,9 @@ package server import ( "context" "fmt" + "net" "net/http" + "sync" "linkmaster-node/internal/config" "linkmaster-node/internal/handler" @@ -14,8 +16,10 @@ import ( ) type HTTPServer struct { - server *http.Server - logger *zap.Logger + ipv4Server *http.Server + ipv6Server *http.Server + logger *zap.Logger + wg sync.WaitGroup } func NewHTTPServer(cfg *config.Config) *HTTPServer { @@ -43,26 +47,90 @@ func NewHTTPServer(cfg *config.Config) *HTTPServer { api.GET("/health", handler.HandleHealth) } - server := &http.Server{ - Addr: fmt.Sprintf(":%d", cfg.Server.Port), + // IPv4 服务器 + ipv4Server := &http.Server{ + Addr: fmt.Sprintf("0.0.0.0:%d", cfg.Server.Port), + Handler: router, + } + + // IPv6 服务器 + ipv6Server := &http.Server{ + Addr: fmt.Sprintf("[::]:%d", cfg.Server.Port), Handler: router, } logger, _ := zap.NewProduction() return &HTTPServer{ - server: server, - logger: logger, + ipv4Server: ipv4Server, + ipv6Server: ipv6Server, + logger: logger, } } func (s *HTTPServer) Start() error { - s.logger.Info("HTTP服务器启动", zap.String("addr", s.server.Addr)) - return s.server.ListenAndServe() + // 启动 IPv4 服务器 + s.wg.Add(1) + go func() { + defer s.wg.Done() + s.logger.Info("HTTP服务器启动 (IPv4)", zap.String("addr", s.ipv4Server.Addr)) + if err := s.ipv4Server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + s.logger.Error("IPv4服务器启动失败", zap.Error(err)) + } + }() + + // 启动 IPv6 服务器 + s.wg.Add(1) + go func() { + defer s.wg.Done() + // 检查系统是否支持 IPv6 + listener, err := net.Listen("tcp6", s.ipv6Server.Addr) + if err != nil { + s.logger.Warn("IPv6不支持或已禁用,跳过IPv6监听", zap.String("addr", s.ipv6Server.Addr), zap.Error(err)) + return + } + + s.logger.Info("HTTP服务器启动 (IPv6)", zap.String("addr", s.ipv6Server.Addr)) + if err := s.ipv6Server.Serve(listener); err != nil && err != http.ErrServerClosed { + s.logger.Error("IPv6服务器启动失败", zap.Error(err)) + } + // Serve 返回后关闭监听器 + listener.Close() + }() + + // 立即返回,服务器在后台运行 + return nil } func (s *HTTPServer) Shutdown(ctx context.Context) error { - return s.server.Shutdown(ctx) + var errs []error + + // 关闭 IPv4 服务器 + if s.ipv4Server != nil { + if err := s.ipv4Server.Shutdown(ctx); err != nil { + errs = append(errs, fmt.Errorf("关闭IPv4服务器失败: %w", err)) + } else { + s.logger.Info("IPv4服务器已关闭") + } + } + + // 关闭 IPv6 服务器 + if s.ipv6Server != nil { + if err := s.ipv6Server.Shutdown(ctx); err != nil { + errs = append(errs, fmt.Errorf("关闭IPv6服务器失败: %w", err)) + } else { + s.logger.Info("IPv6服务器已关闭") + } + } + + // 等待所有 goroutine 完成 + s.wg.Wait() + + if len(errs) > 0 { + return fmt.Errorf("关闭服务器时发生错误: %v", errs) + } + + return nil } func recoveryMiddleware(c *gin.Context) {