How to reliably unlink() a Unix domain socket in Go programming language

老子叫甜甜 提交于 2019-12-05 01:58:57

Here is the complete solution I used. The code I posted in my question was a simplified version for clear demonstration purposes.

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

I sure hope this is good and effective Go code that would make the Go authors proud. It certainly looks so to me. If it is not, that would be embarrassing on my part. :)

For anyone curious, this is part of https://github.com/JamesDunne/go-index-html which is a simple HTTP directory listing generator with some extra features that web servers don't give you out of the box.

You can end your main func with the signal handler and spawn separate go routines for your other tasks instead. That way, you can leverage the defer mechanism and handle all (signal-based or not) shut downs cleanly:

func main() {
    // Create the HTTP server listening on the requested socket:
    l, err := net.Listen("unix", "/tmp/mysocket")
    if err != nil {
        log.Fatal(err)
        return
    }
    // Just work with defer here; this works as long as the signal handling
    // happens in the main Go routine.
    defer l.Close()

    // Make sure the server does not block the main
    go func() {
        log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
    }()


    // Use a buffered channel so we don't miss any signals
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)

    // Block until a signal is received.
    s := <-c
    fmt.Println("Got signal:", s)

    // ...and exit, running all the defer statements
}

In modern Go, you may use the syscall.Unlink() - docs here:

import ( 
    "net"
    "syscall"
    ...
)

...


socketpath := "/tmp/somesocket"
// carry on with your socket creation:
addr, err := net.ResolveUnixAddr("unixgram", socketpath)
if err != nil {
    return err;
}

// always remove the named socket from the fs if its there
err = syscall.Unlink(socketpath)
if err != nil {
    // not really important if it fails
    log.Error("Unlink()",err)
}

// carry on with socket bind()
conn, err := net.ListenUnixgram("unixgram", addr);
if err != nil {
    return err;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!