我有一个 Go 程序在 localhost:8080
上托管一个简单的 HTTP 服务,因此我可以通过 proxy_pass
将我的公共(public) nginx
主机连接到它> 指令,作为反向代理来服务我网站的部分请求。这一切都很好,没有问题。
我想将 Go 程序转换为在 Unix 域套接字而不是本地 TCP 套接字上托管 HTTP 服务,以提高安全性并减少 TCP 不必要的协议(protocol)开销。
问题:
问题是 Unix 域套接字一旦 bind()
就不能被重用,即使在程序终止之后也是如此。第二次(以及之后的每次)我运行 Go 程序,它以 fatal error "address already in use"
退出。
通常的做法是在服务器关闭时unlink()
Unix 域套接字(即删除文件)。但是,这在 Go 中很棘手。我的第一次尝试是在我的主函数中使用 defer
语句(见下文),但如果我用 CTRL-C 之类的信号中断进程,它就不会运行。我想这是可以预料的。令人失望,但并不意外。
问题:是否有关于如何在服务器进程关闭(正常或不正常)时 unlink()
套接字的最佳实践?
这是我的 func main()
的一部分,它启动服务器监听以供引用:
// Create the HTTP server listening on the requested socket:
l, err := net.Listen("unix", "/tmp/mysocket")
if err != nil {
log.Fatal(err)
} else {
// Unix sockets must be unlink()ed before being reused again.
// Unfortunately, this defer is not run when a signal is received, e.g. CTRL-C.
defer func() {
os.Remove("/tmp/mysocket")
}()
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
}
最佳答案
这是我使用的完整解决方案。我在问题中发布的代码是一个简化版本,用于清晰演示。
// Create the socket to listen on:
l, err := net.Listen(socketType, socketAddr)
if err != nil {
log.Fatal(err)
return
}
// Unix sockets must be unlink()ed before being reused again.
// Handle common process-killing signals so we can gracefully shut down:
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
go func(c chan os.Signal) {
// Wait for a SIGINT or SIGKILL:
sig := <-c
log.Printf("Caught signal %s: shutting down.", sig)
// Stop listening (and unlink the socket if unix type):
l.Close()
// And we're done:
os.Exit(0)
}(sigc)
// Start the HTTP server:
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
我当然希望这是让 Go 作者感到自豪的优秀且有效的 Go 代码。在我看来确实如此。如果不是,那对我来说会很尴尬。 :)
对于任何好奇的人,这是 https://github.com/JamesDunne/go-index-html 的一部分这是一个简单的 HTTP 目录列表生成器,具有一些 Web 服务器不提供开箱即用的额外功能。
关于go - 如何在 Go 编程语言中可靠地 unlink() Unix 域套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16681944/