Go Unix 域套接字:绑定地址已在使用中



我有以下服务器代码,它通过 unix 域套接字侦听

package main
import (
"log"
"net"
"os"
"os/signal"
"syscall"
)
func echoServer(c net.Conn) {
for {
buf := make([]byte, 512)
nr, err := c.Read(buf)
if err != nil {
return
}
data := buf[0:nr]
println("Server got:", string(data))
_, err = c.Write(data)
if err != nil {
log.Fatal("Writing client error: ", err)
}
}
}
func main() {
log.Println("Starting echo server")
ln, err := net.Listen("unix", "/tmp/go.sock")
if err != nil {
log.Fatal("Listen error: ", err)
}
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
go func(ln net.Listener, c chan os.Signal) {
sig := <-c
log.Printf("Caught signal %s: shutting down.", sig)
ln.Close()
os.Exit(0)
}(ln, sigc)
for {
fd, err := ln.Accept()
if err != nil {
log.Fatal("Accept error: ", err)
}
go echoServer(fd)
}
}

当我使用 Ctrl+C 关闭它时,信号被捕获并关闭套接字。当我重新运行该程序时,一切正常。

但是,如果正在运行的进程突然被终止,并且程序重新启动,则侦听将失败并显示错误Listen error: listen unix /tmp/go.sock: bind: address already in use

如何优雅地处理这个问题?

我问这个的原因是:我知道突然杀死不是正常的方法,但我的程序应该作为守护程序自动启动,如果我的守护进程重新启动,我希望能够再次收听套接字而不会出错。

也可能是因为先前的实例正在运行,我理解这一点。这里的问题是如何在 Go 中以编程方式识别并处理这种情况。正如这里的答案所指出的,可以在 C 程序中使用 SO_REUSEADDR。围棋有这种可能性吗?另外,C 程序如何处理这个多实例问题。

您需要捕获信号并进行清理;一些示例代码:

func HandleSIGINTKILL() chan os.Signal {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
return sig
}
...
go func() {
<-HandleSIGINTKILL()
log.Info("Received termination signal")
// Cleanup code here
os.Exit(0)
}()

如果您kill -9该过程,这当然不起作用;您需要手动删除套接字(或让您的 init 系统为您完成)。

最新更新