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

时间:2017-05-14 10:24:34

标签: sockets go

我有以下服务器代码,它通过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将失败,并显示错误Listen error: listen unix /tmp/go.sock: bind: address already in use

如何慷慨地处理这个?

我之所以这样问是:我知道突然查杀不是正常的方法,但我的程序应该作为守护进程自动启动,如果我的守护进程重新启动,我希望能够再次收听套接字没有这个错误。

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

1 个答案:

答案 0 :(得分:0)

你需要抓住信号和清理;一些示例代码:

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系统为您执行此操作)。