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

I'm having the following server code, which listens via unix domain socket

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)
    }
}

When I close it using Ctrl+C, then the signal is captured and the socket is closed. When I rerun the program, everything works fine.

However, if the running process is abruptly killed, and if the program is restarted, the listen fails with the error Listen error: listen unix /tmp/go.sock: bind: address already in use

How to graciously handle this?

The reason why I ask this is: I know that abruptly killing is not the normal method, but my program shall be launched automatically as a daemon and if my daemon is restarted, I want to be able to listen to the socket again without this error.

It could also be because of a prior instance running, which I understand. The question here is how to programmatically identify in Go and handle this situation. As pointed in the answer here, one can use SO_REUSEADDR in C programs. Is there such a possibility in Go? Also, how do C programs handle this multiple instance problem.

You need to catch the signal and cleanup; some example code:

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)
}()

This will of course not work if you kill -9 the process; you will need to manually remove the socket (or have your init system do it for you).