You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go中实现多端口多路由监听并控制各监听组的启停状态?

多端口多路由独立启停的Go内置包实现

要实现多组带独立路由的端口监听,且能单独控制启停,用Go内置的http.ServeMux和http.Server就能搞定。每个监听组对应独立的路由复用器和服务器实例,配合context实现优雅启停。

核心改造点

  • 为每个location实例创建专属的http.ServeMux,用来注册该实例下的所有路由
  • 用context管理服务器的生命周期,通过取消context触发优雅停机
  • 维护服务注册表,方便定位和操作任意监听实例

修改后的代码示例

import (
    "context"
    "log"
    "net/http"
    "sync"
)

// 补充context相关字段的location结构体
type location struct {
    root          string
    locationType  int // loadBalancing、fileService等常量
    hashRing      *HashRing // 假设已定义的负载均衡结构
    httpService   *http.Server
    stopCtx       context.Context
    stopCancel    context.CancelFunc
    // 其他原有字段...
}

const (
    loadBalancing = 1
    fileService   = 2
)

func (location *location) listen(mu *sync.Mutex, servicesPoll *map[string]*location) {
    // 1. 创建专属路由复用器
    mux := http.NewServeMux()
    
    // 2. 注册该实例下的路由和处理函数
    switch location.locationType {
    case loadBalancing:
        // 注册负载均衡相关路由
        mux.HandleFunc("/proxy/", func(w http.ResponseWriter, r *http.Request) {
            location.hashRing.forward(w, r, mu)
        })
        mux.HandleFunc("/status/", location.checkStatus)
    case fileService:
        // 注册文件服务相关路由
        mux.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
            location.getFile(w, r, mu)
        })
        mux.HandleFunc("/upload/", location.uploadFile)
    }

    // 3. 创建带context的服务器实例
    location.stopCtx, location.stopCancel = context.WithCancel(context.Background())
    server := &http.Server{
        Addr:    location.root,
        Handler: mux,
    }
    location.httpService = server
    (*servicesPoll)[location.root] = location

    // 4. 启动服务器,同时监听停止信号
    go func() {
        <-location.stopCtx.Done()
        // 优雅停机,等待现有请求处理完成
        if err := server.Shutdown(context.Background()); err != nil {
            log.Printf("server %s shutdown error: %v", location.root, err)
        }
    }()

    err := server.ListenAndServe()
    if err != nil && err != http.ErrServerClosed {
        log.Printf("server %s listen error: %v", location.root, err)
    }

    // 停机后从注册表移除
    mu.Lock()
    delete(*servicesPoll, location.root)
    mu.Unlock()
}

// 停止指定location的服务
func (location *location) Stop() {
    if location.stopCancel != nil {
        location.stopCancel()
    }
}

// 示例:停止所有服务
func StopAllServices(mu *sync.Mutex, servicesPoll *map[string]*location) {
    mu.Lock()
    defer mu.Unlock()
    for _, loc := range *servicesPoll {
        loc.Stop()
    }
}

// 假设的辅助方法
func (location *location) checkStatus(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("load balancer is running"))
}

func (location *location) uploadFile(w http.ResponseWriter, r *http.Request) {
    // 文件上传逻辑实现
}

关键说明

  • 路由分离:每个location的ServeMux独立管理自己的路由规则,不同端口/实例的路由互不干扰
  • 优雅启停:通过context.WithCancel生成的cancel函数触发Shutdown,服务器会停止接收新请求,等待现有请求处理完毕后退出
  • 服务管理:servicesPoll注册表记录所有运行中的服务,方便单独或批量启停

内容的提问来源于stack exchange,提问作者lvyonghuan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 17:32:46