【问题标题】:Golang close net listenerGolang 关闭网络监听器
【发布时间】:2015-09-06 06:59:45
【问题描述】:

我无法关闭侦听器,以便在同一端口上重新打开它。我正在编写一个可热配置的代理服务器 - 即它的作用(重定向/阻止等)可以即时调整。代理在 go 例程中运行。我遇到的问题是,当我重新配置侦听器和代理时,侦听器仍在使用先前配置中的该端口。 (仅供参考的监听器是一个全局指针) 我正在尝试类似:

杀死听众:

func KillProxy() {
    
    if listener != nil {
        log.Println(" *** TRYING TO STOP THE PROXY SERVER")
        (*listener).Close()
        listener = nil
    }
}

在重新配置之前:

log.Println("listener (S1): ", listener)
if listener == nil {
    // Start the listener to listen on the connection.
    l, err := net.Listen(CONN_TYPE, CONN_HOST + ":" + CONN_PORT)

    if err != nil {
        log.Println("error here: ", err)
    }    
    listener = &l //set it as a pointer to the newly created listener
} 
log.Println("listener (S2): ", listener)

但这似乎不起作用 - 我收到错误:

监听器(S1):

此处出错:listen tcp 0.0.0.0:8080: bind: address already in use

监听器(S2):0xc2080015e0

然后是一个巨大的堆栈跟踪,总结为:

恐慌:运行时错误:无效的内存地址或 nil 指针取消引用

针对 JIM 进行编辑:

有趣的重新指针。好的。我没有处理等待套接字关闭,我不知道应该怎么做。我使用的代理库是这个:https://github.com/abourget/goproxy。事情发生的顺序是:

KillProxy()
refreshProxy()

refreshProxy 包含上面发布的代码,它试图重新调整侦听器的用途。 refreshProxy() 发生的最后一件事是:

go http.Serve(*listener, proxy)

因此,如果我将侦听器恢复为全局变量,而不是指针,我可以创建 KillProxy():

func KillProxy() {
    if listener != nil {
        listener.Close()
        listener = nil
    }
}

然后将监听器再次设置为

listener, err := net.Listen(CONN_TYPE, CONN_HOST + ":" + CONN_PORT) 
    if err != nil {
        log.Println("error here: ", err)
    }    

但是在尝试重新创建监听器对象之前,我不知道如何等待并检查套接字是否已关闭?

【问题讨论】:

  • 永远不要使用指向接口的指针,它只会混淆问题并且可能与您的恐慌有关。如果端口已绑定,那么您无需等待套接字关闭即可再次绑定。请展示实际的代码处理方式。
  • 如果err != nil,我认为你不应该使用l。我不记得约定是什么,但我可以想象它只是垃圾。
  • @JimB 我已经编辑了我的原始帖子。
  • 您必须在接受循环周围处理关闭套接字,因此请检查 http.Serve 重新调整的错误。另外,不要将监听器设置为 nil(尝试使用竞赛检测器运行)
  • @JimB 好的,我可以针对 .Serve 进行测试,但如果出现错误,我是否需要延迟或重新调用它? Ok 将删除 KillProxy() 中的 listener = nil。抱歉,种族检测器是什么?你知道这样的例子吗?

标签: go proxy listener goroutine


【解决方案1】:

好的,这远非完美,但我发现没有出错的唯一方法是在我的代码中人为地延迟,以便套接字有时间关闭。 这不是很好,因为这意味着代理在套接字关闭时关闭了 2 秒,但至少它不会出错。 如果有人有更好的解决方案,我想听听

func KillProxy() {
    if listener != nil {
        listener.Close()
        log.Println("waiting for socket to close")
        time.Sleep(2 * time.Second)
    }
}

【讨论】:

  • 使用睡眠是协调并发的最糟糕的方式,尤其是因为仍然不能保证它不会恐慌。你需要等待 http.Serve 返回,然后启动一个新的监听器。
  • 是的,我现在已经正确修复了这个问题,没有任何延迟。我现在有一个结构体,它包裹着一个监听器并处理自己的关闭。花了一段时间破解,但最终到达那里
猜你喜欢
  • 2010-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多